java - 如何在按下/单击窗口标题栏时得到通知

标签 java swing

我正在使用 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/

相关文章:

java - 提高 bufferedImage.drawImage 的性能

java - 将 PNG 转换为 Bitmap 到 Byte[] 以存储在 SQL 中

java - Swing 应用程序的丰富日历组件

Java Swing EDT 和并发

java - 任意 JRE 上的 "java.lang.InternalError: HTHEME is null"(Windows)

java - 非常简单的构造函数问题,我就是无法得到。 java

java - Kerberos WAS 7 回退到应用程序身份验证 (LDAP)

java - 如何对整数使用类似 charAt 的东西

Java JTextPane 斜体帮助

java - 具有初始化变量的 NPE