【问题标题】:Is it possible to bring JFrame to front but NOT focus?是否可以将 JFrame 放在前面但不聚焦?
【发布时间】:2011-06-14 21:47:48
【问题描述】:

我正在编写一个定期弹出 JFrame 的 Java 应用程序(Swing GUI)。

是否有可能以某种方式将窗口置于前面(foo.setAlwaysOnTop(true) 会更好)但没有使其成为焦点?

有些人在打字时会不时将视线从屏幕上移开看他们的键盘,我敢肯定,如果这个窗口总是能捕捉到键盘焦点,人们会非常恼火,因为这会导致他们迷失方向每次弹出时都会被击键很多次。

在其他情况下,即使用户实际上能够在不一直看键盘的情况下打字,弹出一个窗口并获得焦点也可能导致弹出窗口本身发生不必要的操作(一些Tab+例如Enter 组合,用户不小心选择了一个她本来不会选择的选项)。

提前致谢!

更新

正如 Jonas 建议的那样,如果在渲染窗口后调用 foo.setFocusableWindowState(false); 似乎可以工作(仅在 Gnome 上测试过)。

这不起作用:

foo.setFocusableWindowState(false);
foo.setVisible(true);
foo.setFocusableWindowState(true);

但是,这确实

foo.setFocusableWindowState(false);
foo.setVisible(true);
Thread.sleep(1000);
foo.setFocusableWindowState(true);

我必须看看是否有我可以捕捉/收听的事件允许我在适当的时候做foo.setFocusableWindowStatue(true);

我认为我的问题已经解决了。

【问题讨论】:

  • 你有没有找到在渲染帧时监听的事件?
  • 有没有人在这里找到可以收听的活动?

标签: java swing jframe


【解决方案1】:

这可能有效:

foo.setFocusableWindowState(false);

【讨论】:

  • 这实际上似乎有效,但是当我允许我将setFocusableWindowState 回到true 时,我要么必须设置一个计时器,要么找到一些要听的事件。
  • @Johann 你也可以尝试使用Window 而不是JFrame。我认为你有更多的可能性来控制焦点。
【解决方案2】:

从 Java 1.7 开始,您可以调用

frame.setAutoRequestFocus(false);

【讨论】:

  • 这对我有用 - 谢谢!
【解决方案3】:

我最近遇到了同样的问题,暂时的解决方案是:

JFrame frame = ...;
frame.setExtendedState(JFrame.NORMAL);
frame.setAlwaysOnTop(true);
frame.requestFocus();
frame.setAlwaysOnTop(false);

【讨论】:

  • 如果只有一个 JFrame 并且没有任何后台任务,请启动您自己的线程(如果需要,请使用指向该线程的链接),这样做太难了没有 setVisible(true/flase),但是这个动作在屏幕上是可见的,答案是使用 JDialog,只有那个(意味着 Windows 操作系统)你可以做到这一点而不会出现次要问题
  • 这根本不是真的,因为我的应用程序中运行了多个 JFrame。当用户描述与我遇到的完全相同的问题时,为什么要启动一个新线程,但解决方案不完整?至于 JDialog,它并不总是适合窗口的预期用途,这也是我的情况。
  • 是的,也许我这样做没有闪烁,但是这段代码比这个线程长,真的不是好方法,不要在两个或多个 JFrame 之间切换 Focus,将一个 JFrame 带到另一个,Focus (与 JFrame 或 JDialog 相同)来自 Native OS 并且是异步的,因此很难管理,
【解决方案4】:

建议:在创建 Frame 的 GUI Component 中,连续调用 2 次:

frameJustCreated.requestFocus();
this.requestFocus();

第一个将新 JFrame 的窗口置于顶部,第二个将用户正在输入的窗口保持在顶部。

【讨论】:

  • 非常抱歉!我应该提到这是我的程序负责的唯一窗口。 “其他”窗口只是用户正在运行的其他程序..
【解决方案5】:

如果您想在事件中调用 setFocusableWindowState(true)(因此,不要等待例如 1 秒),您可以添加一个 WindowListener(例如,从 WindowAdapter 派生)来更改属性:

    appFrame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowOpened(WindowEvent e) {
            super.windowOpened(e);
            e.getWindow().setFocusableWindowState(true);
        }
    });

    appFrame.setFocusableWindowState(false);
    appFrame.setVisible(true);

【讨论】:

    【解决方案6】:

    JInternalFrame toFront() 调用moveToFront()

    覆盖moveToFront()

    public void moveToFront() {
            Window window = SwingUtilities.getWindowAncestor(this);
            Component focusOwner = (window != null) ? window.getFocusOwner() :
                                    null;
            boolean descendant = false;
    
            if (window != null && focusOwner != null &&
                          SwingUtilities.isDescendingFrom(focusOwner, this)) {
                descendant = true;
                requestFocus();
            }
    
            super.moveToFront();
    
            if (descendant) {
                focusOwner.requestFocus();
            }
        }
    

    修复是在 moveToFront 中检查孩子是否有焦点,如果有,则暂时请求将焦点放在内部框架上。在内部框架移动到前面之后,然后请求将焦点重新放在先前聚焦的组件上。这将确保生成适当的事件。

    参考 https://bugs.openjdk.java.net/browse/JDK-4309079

    【讨论】:

      猜你喜欢
      • 2019-06-08
      • 2011-10-15
      • 2019-07-25
      • 2012-12-23
      • 2019-08-04
      • 2020-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多