【发布时间】:2014-11-25 21:19:58
【问题描述】:
我正在使用 JWindow(不是 JPopupMenu)开发自动下拉建议窗口(如 Google)。我的下拉 JWindow 不是可聚焦的,也不是模态的(文本字段需要在用户键入时保持焦点)。
每当用户在下拉菜单之外的任何位置按下鼠标,或者应用失去焦点或被最小化或按下退出键时(基本上就像 JPopupMenu 的行为),我都想关闭下拉菜单。
我可以正常工作除了当用户按下主框架标题栏时我不知道如何获取事件(这会导致主框架位于下拉列表的前面)。 p>
我担心没有事件发生,因为我没有收到这个听众的任何东西:
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);
}
}
【问题讨论】:
-
你试过
WindowListener.windowActivated()吗? -
我相信我的 AWT 事件监听器也应该得到所有的窗口事件,包括 windowActivated。但我会再试一次......(经过测试:不,当我最小化和恢复我的主框架时,我确实收到了 windowActivated 事件,但不仅仅是通过单击窗口标题栏)。
-
我记得,这是不可能的,或者至少非常困难。参见例如bugs.java.com/bugdatabase/view_bug.do?bug_id=6491619
-
当您单击包含窗口的本机标题栏或边框时,JComboBox 弹出窗口会关闭,显然 JPopupMenus 也会这样做,因此肯定有办法做到这一点。我在这里问了一个相关的问题:stackoverflow.com/questions/43810491/…