I have a JFrame (undecorated) with a Glasspane. This Frame opens a JDialog (also undecorated and has also a glassPane) and hides itself (setVisible(false)). The Glasspanes are set with .setGlassPane(). The Dialog is opened with the Frame as owner.
The GlassPane extends a JPanel and implements AWTEventListener. I use it for resizing the Frames and Dialogs, so it knows it's parent (the Frame/Dialog) - this is called "target".
The Events inside the GlassPane are handled like this:
public void eventDispatched(AWTEvent event) {
if (target instanceof JFrame) {
e = SwingUtilities.convertMouseEvent(
((MouseEvent) event).getComponent(),
(MouseEvent) event, ((JFrame) target).getGlassPane());
} else if (target instanceof JDialog) {
e = SwingUtilities.convertMouseEvent(
((MouseEvent) event).getComponent(),
(MouseEvent) event, this);
}
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
this.startPos = target.getLocationOnScreen();
}
}
At "target.getLocationOnScree" I get an IllegalComponentStateException, when the JFrame is hidden and I click on the JDialog. It says "component must be showing on the screen to determine its location". This is because the GlassPane of the JFrame gets the event. But the Glasspane of the JDialog should get it. I think, the Glasspane of the JFrame is in front of the JDialog. But why?
Thanks for helping!
Edit:
Here is an example:
import java.awt.AWTEvent;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import javax.swing.JDialog;
import javax.swing.JFrame;
public class Main {
static JFrame frame;
static JDialog dialog;
public static void main(String[] args) {
frame = new JFrame();
frame.setSize(600,600);
GlassPane frameGlas = new GlassPane(frame);
frame.setGlassPane(frameGlas);
frame.setVisible(true);
frameGlas.setVisible(true);
dialog = new JDialog(frame);
dialog.setSize(100, 100);
GlassPane dialogGlas = new GlassPane(dialog);
dialog.setGlassPane(dialogGlas);
AWTEventListener al = (AWTEventListener) frameGlas;
Toolkit.getDefaultToolkit().addAWTEventListener(
al,
AWTEvent.MOUSE_MOTION_EVENT_MASK
| AWTEvent.MOUSE_EVENT_MASK);
dialogGlas.setVisible(true);
dialog.setVisible(true);
}
}
import java.awt.AWTEvent;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GlassPane extends JPanel implements AWTEventListener {
/**
*
*/
private static final long serialVersionUID = 5110857185182004819L;
private final Window target;
public GlassPane(Window target) {
super(null);
this.target = target;
}
public void eventDispatched(AWTEvent event) {
if (event instanceof MouseEvent) {
MouseEvent originalEvent = (MouseEvent) event;
MouseEvent e = originalEvent;
if (target instanceof JDialog) {
e = SwingUtilities.convertMouseEvent(
((MouseEvent) event).getComponent(),
(MouseEvent) event, this);
}
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
Point p = target.getLocationOnScreen();
System.out.println(p.getX());
}
}
}
}
Looking at you source code, you only ever register the frame
's glass pane to the AWTListener. Now, on the surface, this doesn't seem like a bad thing. The AWTListener
will be notified of ALL the mouse events in the system, but the instance of GlassPane
that is actually receiving the events will only know about the frame
...
Basically, this means that the dialogGlas
will never receive any events, as it's not registered.
First, you need to register both the frameGlas
and dialogGlas
as listeners.
Second, you shouldn't be trying to "guess" the target. MouseEvent
(in fact all events) have a source. You should be comparing the source with the target
so you can react to events only when they occur on components you're interested in...
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
static JFrame frame;
static JDialog dialog;
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
frame = new JFrame();
frame.setSize(600, 600);
GlassPane frameGlas = new GlassPane(frame);
frame.setGlassPane(frameGlas);
frame.setVisible(true);
frameGlas.setVisible(true);
dialog = new JDialog(frame);
dialog.setSize(100, 100);
GlassPane dialogGlas = new GlassPane(dialog);
dialog.setGlassPane(dialogGlas);
dialogGlas.setVisible(true);
dialog.setVisible(true);
// Register a listener for the frameGlas
Toolkit.getDefaultToolkit().addAWTEventListener(
frameGlas,
AWTEvent.MOUSE_MOTION_EVENT_MASK
| AWTEvent.MOUSE_EVENT_MASK);
// Register a listener for the dialogGlas
Toolkit.getDefaultToolkit().addAWTEventListener(
dialogGlas,
AWTEvent.MOUSE_MOTION_EVENT_MASK
| AWTEvent.MOUSE_EVENT_MASK);
}
});
}
public class GlassPane extends JPanel implements AWTEventListener {
private static final long serialVersionUID = 5110857185182004819L;
private final Window target;
public GlassPane(Window target) {
super(null);
this.target = target;
}
@Override
public void eventDispatched(AWTEvent event) {
if (event instanceof MouseEvent) {
MouseEvent originalEvent = (MouseEvent) event;
MouseEvent e = originalEvent;
Component source = e.getComponent();
System.out.println("Source: " + source);
System.out.println("Target: " + target);
if (target != null && target.equals(source)) {
e = SwingUtilities.convertMouseEvent(
((MouseEvent) event).getComponent(),
(MouseEvent) event, this);
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
Point p = target.getLocationOnScreen();
System.out.println(p.getX());
}
}
}
}
}
}
Now, off the top of my head, the problem you're having with MouseListener
is that they are greedy, they prevent the events from cascading beyond the component they are registered on.