我有一个带有Glasspane的JFrame(未装饰)。此框架打开一个JDialog(也未装饰,也具有glassPane)并隐藏自身(setVisible(false))。Glasspanes使用.setGlassPane()设置。将以框架作为所有者打开对话框。
GlassPane扩展了JPanel并实现了AWTEventListener。我使用它来调整“框架”和“对话框”的大小,因此它知道它是父项(“框架/对话框”)-这称为“目标”。
GlassPane内部的事件按以下方式处理:
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(); } }
在隐藏JFrame并单击JDialog时,在“ target.getLocationOnScree”处收到一个IllegalComponentStateException。它说:“必须在屏幕上显示组件才能确定其位置”。这是因为JFrame的GlassPane获取了事件。但是JDialog的Glasspane应该可以得到它。我认为,JFrame的Glasspane位于JDialog的前面。但为什么?
感谢您的帮助!
编辑:
这是一个例子:
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()); } } } }
查看源代码,您只需将frame的玻璃窗格注册到AWTListener。现在,从表面上看,这似乎不是一件坏事。系统AWTListener会将所有鼠标事件通知给,但是GlassPane实际上接收到该事件的实例只会知道frame…
frame
AWTListener
GlassPane
基本上,这意味着dialogGlas不会接收任何事件,因为它尚未注册。
dialogGlas
首先,您需要同时注册frameGlas和dialogGlas作为侦听器。
frameGlas
其次,您不应该试图“猜测”目标。 MouseEvent(实际上所有事件)都有来源。您应该将来源与进行比较,target以便仅在事件发生在您感兴趣的组件上时才对事件做出反应…
MouseEvent
target
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()); } } } } } }
现在,让我烦恼的MouseListener是,他们遇到的问题是贪婪,它们阻止事件层叠到所注册的组件之外。
MouseListener