我正在使用 JWindow(不是 JPopupMenu)开发自动下拉建议窗口(如 Google)。我的下拉 JWindow 不可聚焦且非模态(文本字段需要在用户键入时保持焦点)。
只要用户在下拉菜单外的任何地方按下鼠标,或者如果应用程序失去焦点或最小化或按下转义键(基本上就像 JPopupMenu 的行为),我都想关闭下拉菜单。
我让它正常工作除了我不知道如何在用户按下主框架标题栏时获取事件(这会导致主框架位于下拉列表的前面)。
我担心没有这方面的事件,因为我没有收到这个听众的任何东西:
Toolkit.getDefaultToolkit().addAWTEventListener(myTestListener, Integer.MAX_VALUE);
无论如何,JPopupMenu 是如何实现这种行为的?
编辑:添加 SSCCE:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class SSCCE
{
public static void main(String[] args) throws Exception
{
final JFrame frame = new JFrame();
JButton button = new JButton("open popup");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
openPopup(frame);
}
});
frame.setLayout(new FlowLayout());
frame.add(button);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static void openPopup(JFrame frame)
{
final JWindow popupWindow = new JWindow();
popupWindow.setFocusable(false);
popupWindow.setSize(400, 400);
popupWindow.setLocation(frame.getX() + 200, frame.getY() + 200);
((JComponent) popupWindow.getContentPane()).setBorder(new MatteBorder(1, 1, 1, 1, Color.RED));
popupWindow.setVisible(true);
AWTEventListener awtEventListener = new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent e)
{
System.out.println(e.toString());
if(e instanceof MouseEvent
&& ((MouseEvent) e).getID() == MouseEvent.MOUSE_PRESSED //
|| e instanceof FocusEvent
&& ((FocusEvent) e).getID() == FocusEvent.FOCUS_LOST //
|| e instanceof ComponentEvent
&& ((ComponentEvent) e).getID() == ComponentEvent.COMPONENT_MOVED
&& e.getSource() != popupWindow //
|| e instanceof ComponentEvent && ((ComponentEvent) e).getID() == ComponentEvent.COMPONENT_RESIZED
&& e.getSource() != popupWindow//
|| e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_STATE_CHANGED //
|| e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_ACTIVATED //
|| e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_DEACTIVATED //
|| e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_GAINED_FOCUS //
|| e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_LOST_FOCUS //
|| e instanceof KeyEvent && ((KeyEvent) e).getKeyCode() == KeyEvent.VK_ESCAPE //
)
{
popupWindow.setVisible(false);
Toolkit.getDefaultToolkit().removeAWTEventListener(this);
}
}
};
Toolkit.getDefaultToolkit().addAWTEventListener(awtEventListener, 0xFFFFFFFF);
}
}
最佳答案
首先,首先查看 Toolkit#addAWTEventListener
的文档
Parameters:
listener - the event listener.
eventMask - the bitmask of event types to receive
eventMask
是您要接收的事件 ID 的位掩码。好吧,它没有那么壮观,但它的意思是,你应该传递一个你感兴趣的事件 id 的 or'ed 列表......
现在问题变成了,我们对哪些事件感兴趣以及我们如何获得 id 的...
嗯,AWTEvent
包含与 Toolkit
一起使用的事件 ID 列表,AWTEvent.WINDOW_FOCUS_EVENT_MASK
甚至可能AWTEvent.FOCUS_EVENT_MASK
可能会有用。
Toolkit.getDefaultToolkit().addAWTEventListener(myTestListener,
AWTEvent.WINDOW_FOCUS_EVENT_MASK |
AWTEvent.FOCUS_EVENT_MASK);
例如……
import java.awt.AWTEvent;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.FocusEvent;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestFocus {
public static void main(String[] args) {
new TestFocus();
}
public TestFocus() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
if (event instanceof WindowEvent) {
System.out.println("WindowEvent");
WindowEvent evt = (WindowEvent) event;
if (evt.getID() == WindowEvent.WINDOW_GAINED_FOCUS) {
System.out.println("I got you babe");
} else if (evt.getID() == WindowEvent.WINDOW_LOST_FOCUS) {
System.out.println("Don't leave me!");
}
} else if (event instanceof FocusEvent) {
System.out.println("FocusEvent");
}
}
}, AWTEvent.WINDOW_FOCUS_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
}
}
当焦点状态发生变化时,这些会告诉您,然后您需要检查 KeyboardFocusManager#getFocusOwner
和/或 KeyboardFocusManager#getGlobalFocusedWindow
以确定您的窗口是否仍然具有焦点。
同样,您可以尝试使用 KeyboardFocusManager#addPropertyChangeListener
并监视对 KeyboardFocusManager
...
关于java - 如何在按下/单击窗口标题栏时得到通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27136875/