Skip to main content

JXLayer contains method

2 replies [Last post]
skjalgb
Offline
Joined: 2006-12-28

I have a special case of use for JXLayer without the use of a LayerUI . This is a i18n keyboard for touch panels. However, as demonstrated in the small sample program underneath, mouse events are (in my opinion) incorrectly filtered out in the current implementation of JXLayer. There are several ways around the problem, but I think the best would be to change a line of code in the contains method. What do you think?

Best regards
Skjalg Bjørndal

/**
* Have a problem when using JXLayer without a painter, since it then filters out mouse events.
* This test demonstrates the effect, and a work around.
* <p>
* First run the program as is. When you move the mouse over the two textfields, you will notice that the
* mouse cursor does not change, and you cannot activate the fields.
* <p>
* Next change
* <pre>
* inputLayer.setGlassPane(Keyboard.getInstance());
*

* with
*
 * inputLayer.setGlassPane(Keyboard.getInstance2());
*

* You will now observe that the mouse events are properly routed to underlying text fields as desired.
*
* @author skjalg.bjorndal
* @since 20.jun.2008
*/
public class Keyboard extends JPanel {

JButton a = new JButton("A");
JButton b = new JButton("B");
JButton c = new JButton("C");

Keyboard() {
super(new BorderLayout());
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
buttonPanel.add(a);
buttonPanel.add(b);
buttonPanel.add(c);
add(buttonPanel, BorderLayout.SOUTH);
setOpaque(false);
}

public static JXLayer getInstance() {
JXLayer keyboard = new JXLayer(new Keyboard());
keyboard.setOpaque(false);
return keyboard;
}

public static JXLayer getInstance2() {
JXLayer keyboard = new KeyboardJXLayer(new Keyboard());
keyboard.setOpaque(false);
return keyboard;
}

public boolean contains(int x, int y) {
System.out.println(x + ", " + y);
Point aPoint = SwingUtilities.convertPoint(this, x, y, a);
Point bPoint = SwingUtilities.convertPoint(this, x, y, b);
Point cPoint = SwingUtilities.convertPoint(this, x, y, c);
return a.contains(aPoint.x, aPoint.y) || b.contains(bPoint.x, bPoint.y) || c.contains(cPoint.x, cPoint.y);
}

public static void main(String[] args) {
JFrame frame = new JFrame("Glass pane test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(400, 300));
frame.setLocationRelativeTo(null);

JPanel inputPanel = new JPanel();
final JTextField field1 = new JTextField(20);
inputPanel.add(field1);
final JTextField field2 = new JTextField(20);
inputPanel.add(field2);

final JXLayer inputLayer = new JXLayer(inputPanel);
inputLayer.setGlassPane(Keyboard.getInstance());
// TODO Exchange the above line with this to properly route the mouse events to the underlying text fields.:
//inputLayer.setGlassPane(Keyboard.getInstance2());
frame.getContentPane().add(inputLayer);

frame.setVisible(true);

}

static class KeyboardJXLayer extends JXLayer {

public KeyboardJXLayer() {
}

public KeyboardJXLayer(V v) {
super(v);
}

public KeyboardJXLayer(V v, LayerUI vLayerUI) {
super(v, vLayerUI);
}

public boolean contains(int x, int y) {
LayerUI layerUI = getUI();
if (isLayerValid()) {
return layerUI.contains(this, x, y);
}

// This must be a better solution, since it will eventually call component.inside(x,y) if method is not overridden.
return getView().contains(x, y);
}

// private method copied from JXLayer
protected boolean isLayerValid() {
return getUI() != null && getUI().isEnabled() && getView() != null
&& getWidth() > 0 && getHeight() > 0;
}

}

}

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
alexfromsun
Offline
Joined: 2005-09-05

Hello Skjalg

Actually JXLayer is designed to only be used with some LayerUI

could you give more details about your special case?

I would appreciate if you re-post your source code wrapped with [ code ] and [ /code ]

(without spaces inside) - it will make it more readable

Thanks

alexp

alexfromsun
Offline
Joined: 2005-09-05

Hello Skjalg

While waiting an answer from you I decipher and compile your test case :-)


I see the problem you are talking about, thanks for reporting it!

I fixed the default layer's glassPane, it works well with its subcomponents now

The example below shows a textField and a button added to the layer's glassPane

the bigButton, wrapped with JXLayer has a custom mouse cursor for test purposes

The best way is to add components directly to the default layer.getGlassPane()

otherwise you should provide your own implementation of contains() method for your glassPane

[code]
import org.jdesktop.jxlayer.JXLayer;

import javax.swing.*;
import java.awt.*;

/**
* This test shows how updated JXLayer works with components, placed on its GlassPane.
* Note that HAND_CURSOR which is set to the Big button works well
* together with the text cursor for the textField from the glassPane
*/
public class MyTest {

private static void createGui() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JButton button = new JButton("Big button");
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

final JXLayer l = new JXLayer(button);

l.getGlassPane().add(new JTextField(10));
l.getGlassPane().add(new JButton("Hello"));
frame.add(l);

frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MyTest.createGui();
}
});
}
}
[/code]



Thanks

alexp