问题
I want to have a JPanel
called mainPanel
and add several components on it; Also I defined a mouseAdapter
and added to my mainPanel
that overrides mouseEntered
and mouseExited
to for example change background color of mainPanel
when mouse entered it. But when mouse entered to mainPanel
and entered to components I added on it (for example labels) mouseExited
event is called; But I don't want this as mouse is in area of mainPanel
; I want it be called just when mouse exited mainPanel
area; and also want this for mouseEntered
. I previously added mouseListeners
to components on mainPanel
but it is not a clear solution. Can anyone tell me a clear way for my purpose?
thanks your attention; Good lock
回答1:
You want the mouseEntered
and mouseExited
to be called on full boundaries. This is, as you have noticed, not directly possible with the "normal" MouseListener
.
The simplest way is to add the listener to all child-components of the panel:
private static void addListenerToAllComponents(JComponent c, MouseListener l) {
c.addMouseListener(l);
for (Component cc : c.getComponents())
if (cc instanceof JComponent)
addListenerToAllComponents((JComponent) cc, l);
}
Full example:
public static void main(String[] args) {
final JFrame frame = new JFrame("Test");
frame.add(new JLabel("Testing"), BorderLayout.NORTH);
final JPanel panel = new JPanel(new GridLayout(2, 1));
panel.setBackground(Color.RED);
MouseListener l = new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
panel.setBackground(Color.BLUE);
}
@Override
public void mouseExited(MouseEvent e) {
panel.setBackground(Color.RED);
}
};
panel.add(new JLabel("Hello"));
panel.add(new JTextField("World!"));
addListenerToAllComponents(panel, l);
frame.add(panel, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
Another workaround (previous answer)...
...is to set a GlassPane and check bounds yourself:
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.add(new JLabel("Testing"), BorderLayout.NORTH);
final JPanel panel = new JPanel(new GridLayout(2, 1));
frame.add(panel, BorderLayout.CENTER);
panel.add(new JLabel("Hello"));
panel.add(new JTextField("World!"));
class GlassPane extends JComponent {
GlassPane(final JComponent c) {
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
Point p = SwingUtilities.convertPoint(e.getComponent(),
e.getPoint(),
c);
if (c.contains(p))
c.setBackground(Color.BLUE);
else
c.setBackground(Color.RED);
}
});
addMouseListener(new MouseAdapter() {
public void mouseExited(MouseEvent e) {
c.setBackground(Color.MAGENTA);
}
});
}
}
GlassPane glass = new GlassPane(panel);
frame.setGlassPane(glass);
glass.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
There are some stuff you need to look in to... Event redistribution is one and might be a problem in your case. Follow this example and implement an event distribution listener on the glass pane:
MouseInputListener i = new MouseInputListener() {
private void redispatchMouseEvent(MouseEvent e) {
Point glassPanePoint = e.getPoint();
Container container = frame.getContentPane();
Point containerPoint = SwingUtilities.convertPoint(
GlassPane.this,
glassPanePoint,
container);
Component component =
SwingUtilities.getDeepestComponentAt(
container,
containerPoint.x,
containerPoint.y);
if (component != null) {
Point componentPoint = SwingUtilities.convertPoint(
GlassPane.this,
glassPanePoint,
component);
component.dispatchEvent(new MouseEvent(component,
e.getID(),
e.getWhen(),
e.getModifiers(),
componentPoint.x,
componentPoint.y,
e.getClickCount(),
e.isPopupTrigger()));
}
}
public void mouseMoved(MouseEvent e) {
redispatchMouseEvent(e);
}
public void mouseDragged(MouseEvent e) {
redispatchMouseEvent(e);
}
public void mouseClicked(MouseEvent e) {
redispatchMouseEvent(e);
}
public void mouseEntered(MouseEvent e) {
redispatchMouseEvent(e);
}
public void mouseExited(MouseEvent e) {
redispatchMouseEvent(e);
}
public void mousePressed(MouseEvent e) {
redispatchMouseEvent(e);
}
public void mouseReleased(MouseEvent e) {
redispatchMouseEvent(e);
}
};
addMouseListener(i);
addMouseMotionListener(i);
回答2:
Getting mouseEvents for a component and all its children is ... tricky to get right. You might consider to rely on stable (and extensively tested :-) code around. The jdk7 way of doing it is to use a JLayer (which internally registers an AWTEventListener as it has all priviledges). For earlier versions, you can use its predecessor JXLayer
来源:https://stackoverflow.com/questions/7062154/java-define-unit-component-for-mouse-events