java swing中如何自行丢失焦点?已知怎样获取没找到如何丢失!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java swing中如何自行丢失焦点?已知怎样获取没找到如何丢失!相关的知识,希望对你有一定的参考价值。

参考技术A 你好,按照windows的程序处理方式,一个时间必须有一个事物是聚集的。所以你这个问题的答案是,通过设置另一个控件为焦点,来实现你的目标控件失焦。
如果你想手动让它失去焦点,可以在执行一个动作时,把另外一个控件.setFocus()。
如果你是想让它自动失去焦点,可以开一个子线程,等过了多少秒后,它自动对另一个控件.setFocus()。

Java Swing如何让JFrame获得焦点

【中文标题】Java Swing如何让JFrame获得焦点【英文标题】:Java Swing how to let the JFrame gain focus 【发布时间】:2020-10-01 15:09:44 【问题描述】:

我正在开发一个 java swing 应用程序。我希望达到这样的结果:按下快捷方式让应用程序窗口出现。再次按下快捷键或点击其他地方让应用隐藏。

我使用jkeymaster注册监听全局快捷键事件,效果很好。 但是当用户关注其他一些窗口时,比如 chrome、office ......焦点窗口将是其他应用程序。然后如果用户使用快捷方式。我的应用程序窗口仍会显示,但无法获得焦点。谁能帮我解决它。这是我的代码 sn-p。

    Provider provider = Provider.getCurrentProvider(true);
    // bind shortcut
    provider.register(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), x -> 
        homePage.setVisible(!homePage.isVisible());
        if(homePage.isVisible())
            // TODO: 2020/10/1 request focus here
            homePage.requestFocusInWindow();
            homePage.requestFocus();

            KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
            focusManager.clearGlobalFocusOwner();

            log.info("hasFocus? " + homePage.hasFocus());
            log.info("isActive? " + homePage.isActive());
        
    );

我尝试过的:

    requestFocus 和 requestFocusInWindow,不起作用 我阅读了requestFocus的源代码。它说
     * This method cannot be used to set the focus owner to no Component at
     * all. Use <code>KeyboardFocusManager.clearGlobalFocusOwner()</code>
     * instead.

所以我尝试了 focusManager.clearGlobalFocusOwner() 但它仍然不起作用。

【问题讨论】:

也许grabFocus() 会起作用? @camickr 感谢您的建议,但 JFrame 有 grabFocus 方法。我尝试了 homePage.getRootPane().grabFocus() 但仍然无效。 【参考方案1】:

通常,当您想在父容器中获得焦点时(例如 JPanelJFrame 等),您可以通过将 requestFocusInWindow() 方法调用到它的其中一个子容器中来请求焦点。

我建议你不要在JFrame 中要求焦点。在其中一个组件中调用requestFocusInWindow()

现在就 UX 而言,我会将焦点放回最后关注的组件。为了获得JFrame 的焦点组件,我们调用jframe.getFocusOwner()。但是,如果JFrame 处于状态MINIMIZED 或在后台,由于它没有焦点,getFocusOwner 返回null

因此,为了在调用全局键侦听器之前找到最后一个获得焦点的组件,您也可以为焦点事件注册一个全局 AWT 侦听器:

Toolkit.getDefaultToolkit().addAWTEventListener(e -> 
    if (e.getID() == FocusEvent.FOCUS_LOST) 
        if (e.getSource() instanceof Component) 
            lastFocusedComponent = (Component) e.getSource();
        
    
, FocusEvent.FOCUS_EVENT_MASK);

每次焦点改变时都会触发监听器。因此,您可以安全地获得具有焦点的实际最后一个组件,从而消除成为 null 的机会,因为它是触发事件的组件。

之后你所要做的就是给它打电话requestFocusInWindow

provider.register(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), e -> 
    frame.setVisible(!frame.isVisible());
    if (frame.isVisible())
        SwingUtilities.invokeLater(lastFocusedComponent::requestFocusInWindow);
);

一个有效的完整示例(您可以自己确认焦点已恢复):

public class FocusExample 
    private static Component lastFocusedComponent;

    public static void main(String[] args) 
        SwingUtilities.invokeLater(() -> 

            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JTextField leftField = new JTextField(10);
            JTextField rightField = new JTextField(10);

            frame.setLayout(new FlowLayout());
            frame.add(leftField);
            frame.add(rightField);

            Toolkit.getDefaultToolkit().addAWTEventListener(e -> 
                if (e.getID() == FocusEvent.FOCUS_LOST) 
                    if (e.getSource() instanceof Component) 
                        lastFocusedComponent = (Component) e.getSource();
                    
                
            , FocusEvent.FOCUS_EVENT_MASK);

            Provider provider = Provider.getCurrentProvider(true);

            provider.register(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), e -> 
                frame.setVisible(!frame.isVisible());
                if (frame.isVisible())
                    SwingUtilities.invokeLater(lastFocusedComponent::requestFocusInWindow);
            );

            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        );

    

【讨论】:

感谢您的建议。它确实达到了您实际所说的结果,但这不是我想要的。我希望 JFrame 可以抓住焦点,因为另一个需要是“当 JFrame 失去焦点时 JFrame 应该自动隐藏”。如果 JFrame 出现时无法获得焦点,我无法监控它的 focuslost 事件。我认为不同平台上的实现是不同的。你能给我一些进一步的建议吗?【参考方案2】:

我尝试了一个丑陋的解决方案,使用机器人来模拟用户点击以获得焦点。调用 click 方法时,光标会消失一会儿。但它确实有效(成功获得焦点)

我所做的是:

1.

RobotTool.click((int)windowLocation.getX(), (int)windowLocation.getY());
public class RobotTool 
    private static Robot robot = Singleton.get(Robot.class);

    public static void click(int x, int y)

        Point mouseInitPosition = MouseInfo.getPointerInfo().getLocation();
        int mask = InputEvent.BUTTON1_MASK;
        robot.mouseMove(x, y);
        try
            // wait 100ms to avoid the robot action out of order
            Thread.sleep(100);
        
        catch (InterruptedException e)
            e.printStackTrace();
        
        robot.mousePress(mask);
        robot.mouseRelease(mask);
        robot.mouseMove((int)mouseInitPosition.getX(), (int)mouseInitPosition.getY());
    

【讨论】:

RobotTool 是 java 类吗?我不熟悉它。 @Abra 抱歉,这是我的自定义工具。我刚刚更新了代码。

以上是关于java swing中如何自行丢失焦点?已知怎样获取没找到如何丢失!的主要内容,如果未能解决你的问题,请参考以下文章

Java Swing如何让JFrame获得焦点

关于Java swing组件焦点的问题(我猜可能是焦点的问题) 高分求全面

java怎样将数字变成字符输出

java swing 去掉按钮文字周围的焦点框

Java Swing:JTextField 没有按预期失去焦点

java swing里文本框控制不能输入汉字,或者输入字符串包含汉字在失去焦点事件时提示用户!