【问题标题】:Java on a Mac: How do I detect when my application receives focus?Mac 上的 Java:如何检测我的应用程序何时获得焦点?
【发布时间】:2026-01-11 07:50:02
【问题描述】:

我查看了ApplicationListener,但那里没有。在 Mac 上,这是该应用程序具有等效焦点的时候。它的菜单在顶部菜单栏中。

另外,如果你知道这一点,你能告诉我我的应用程序如何请求自己散焦吗?

【问题讨论】:

    标签: java macos events focus


    【解决方案1】:

    WindowListenerWindowAdapter 中的 windowActivated()windowDeactivated() 的实现会告诉您何时激活或停用窗口。你不需要ApplicationListener

    附录:虽然在这种情况下不需要,但ApplicationListener 中指定的附加功能的透明实现可以在此example 中找到。

    附录:另见How to Write Window Listeners

    附录:我想我明白你的意思了。在使用-Dapple.laf.useScreenMenuBar=true 的示例OSXAdapter 中,菜单会在最后一个窗口(默认为HIDE_ON_CLOSE)关闭时消失。它不是最佳的,但About…Preferences 菜单仍保留在应用程序菜单中;选择任一恢复屏幕菜单。另一种可能是修改com.apple.eawt.Application中的停靠菜单。

    import java.awt.EventQueue;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowEvent;
    import java.awt.event.WindowFocusListener;
    import java.awt.event.WindowListener;
    import java.awt.event.WindowStateListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    
    public class WindowTest extends JFrame implements ActionListener,
        WindowListener, WindowFocusListener, WindowStateListener {
    
        public static final void main(String args[]) throws Exception {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    new WindowTest("One");
                    new WindowTest("Two");
                }
            });
        }
    
        public WindowTest(String name) {
            super(name);
            this.setName(name);
            this.setLayout(new GridLayout(0, 1));
            createButton("Back");
            createButton("Front");
            createButton("Hide");
            this.addWindowListener(this);
            this.addWindowFocusListener(this);
            this.addWindowStateListener(this);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);
            this.pack();
            this.setVisible(true);
        }
    
        private void createButton(String name) {
            JButton b = new JButton(name);
            this.add(b);
            b.addActionListener(this);
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            String s = e.getActionCommand();
            if ("Back".equals(s)) {
                this.toBack();
            } else if ("Front".equals(s)) {
                this.toFront();
            } else {
                this.setExtendedState(JFrame.ICONIFIED);
            }
        }
    
        @Override
        public void windowOpened(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowClosing(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowClosed(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowIconified(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowDeiconified(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowActivated(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowDeactivated(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowGainedFocus(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowLostFocus(WindowEvent e) {
            System.out.println(e);
        }
    
        @Override
        public void windowStateChanged(WindowEvent e) {
            System.out.println(e);
        }
    
    }
    

    【讨论】:

    • 问题是,我使用 frame.setVisible(false) 隐藏了我的窗口,它隐藏了窗口,但不像 Mac 的“隐藏”选项那样起作用。它隐藏了框架,但应用程序保留了焦点。使用frame.toBack() 也不起作用;应用程序保留了焦点,只是窗口被移到了后面。在 Mac 上,当您隐藏应用程序时,该应用程序会隐藏其所有窗口并散焦,并在您为应用程序提供焦点时将它们全部取消隐藏。但是,使用frame.setVisible(),即使您将应用程序散焦并重新获得焦点,它也不会重新出现。
    • (续)它们是完全不同的方法,setVisible() 和 Mac 的隐藏功能。问题是,我已经使用了 WindowListener,但是当我给它焦点时窗口不会重新出现,所以它不起作用。你看到我的大问题了吗?这些我都试过了。你有什么其他的建议?我知道您可能没有使用 Mac 的经验,但您过去一直很有帮助。
    • @Stuart: toBack() 不承诺专注。 AFAIK,切换应用程序是用户的权限。上面的示例显示了两个窗口的 Window 事件,但您也可以浏览本教程。
    • 我已经在使用 OSXAdapter,但是还不够。除其他外,我根本无法管理或检测应用程序焦点。我希望我能找到一种方法来做到这一点......
    • 我不知所措。 OSXAdapter 似乎与这个问题无关,示例并没有使用它。我在最前面的窗口中看到 WINDOW_LOST_FOCUS 和 WINDOW_GAINED_FOCUS 事件,因为我在应用程序之间按 alt-tab 或在示例窗口之间按 alt-~。
    【解决方案2】:

    你能告诉我我的申请如何 可以请求散焦吗?

    你可以试试:

    frame.toBack();
    

    如果这不起作用,那么您可以图标化您的应用程序,在这种情况下,焦点应该转到前一个应用程序。

    frame.setExtendedState(...);
    

    【讨论】:

      【解决方案3】:

      Java 编程语言独立于平台。与其阅读 Apple 的参考文档,不如使用官方的Java API Reference Documentation。在那里您可以找到JFrameWindowListenerWindowAdapter 的文档。您可以使用addWindowListener 函数在JFrame 上注册一个WindowListener。窗口侦听器可用于拦截和处理各种与窗口相关的事件,包括激活/停用(哪个窗口位于顶部)或获得焦点/失去焦点(哪个窗口将接收键盘事件)。如果您提供自己的 WindowListener 并且不想实现每个函数,则 WindowAdapter 对此很有用,因为它实现了 WindowListener 但为每个函数提供了空定义。至于散焦(你的意思),toBack 可以用于此,而toFront 则相反。

      编辑
      大部分信息已在以前的帖子中提供;但是,我添加了这个来强调:

      • Java 是一种独立于平台的语言。
      • Java 是 Sun Microsystems(现为 Oracle)的产品。
      • 因此,使用 Sun 的官方 Java API Reference Documentation 比依赖 Apple 提供的任何参考文档更有意义,因为官方 API 参考文档中包含的任何内容都适用于所有平台;然而,Apple 参考文档中的任何内容都可能非常适合 Apple 的实施。
      • JFrame 的参考文档来自官方的权威参考文档,提供了回答问题所需的所有信息(因此还有一个理由是查阅官方 API 参考文档,而不是依赖 Apple 的文档)。

      【讨论】:

      • -1,WindowListener 在 6 小时前被建议。 toBack() 是在 5 小时前提出的。我认为没有理由重复这些建议。
      • 此外,ApplicationListener 旨在补充而不是取代核心 UI。有关我的答案中引用的 OSXAdapter 示例,请参阅 README.txt
      • @camickr,我想强调官方参考文档的使用(见我的编辑)。此外,其他人未能指出Java术语中的“焦点”意味着键盘焦点(不是哪个窗口在顶部),我的回答也给出了。
      最近更新 更多