当 JDialog 可见时,将焦点放在 JDialog 中的 JTextField

Put focus on a JTextField in JDialog when latter made visible

我有一个 JDialog 的子类...重写的 setVisible 方法如下所示:

public void setVisible( boolean visible ){
    super.setVisible( visible );

    if( visible ){
        inputJTF.requestFocus();
    }
}

事实上,当我显示 JDialog 时,焦点 在 JTF 上...但后者恰好也是 "first" 组件(NORTH 面板) JDialog,所以这并不奇怪。

但我的测试代码告诉我其他事情:

    EventQueue.invokeAndWait(new Runnable() {
        @Override
        public void run() {
            app.mainFrame.searchDlg.setVisible( true );

            // all 3 of these asserts fail...
            assertTrue( app.mainFrame.searchDlg.inputJTF.hasFocus() );
            Component focusOwner = app.mainFrame.searchDlg.getFocusOwner();
            assertFalse( focusOwner == null );
            assertTrue( String.format( "# focus owner %s", focusOwner.getClass()), focusOwner ==  app.mainFrame.searchDlg.inputJTF );

        }
    });

...所以实际上我被告知 "focus owner" 为空...并且 JTF 没有焦点。谁能解释一下这是怎么回事?

大多数对话框都是模态的,也就是说setVisible(true)语句之后的语句直到对话框关闭才会执行。

默认情况下,焦点将转到对话框中的第一个组件。

如果出于某种原因您需要专注于不同的组件,请查看 Dialog Focus 的解决方案,让您控制哪个组件获得焦点。

此解决方案使用 AncestorListener 在组件显示在可见 dialog/frame 上后将焦点放在组件上。

啊哈...结果证明这是 "Gotcha" JUnit 和 Java GUI 的事情之一。

我的代码中的测试失败了...但以下代码没有:

    EventQueue.invokeAndWait(new Runnable() {
        @Override
        public void run() {
            searchDlg.setVisible( true );
            assertTrue( searchDlg.queryString == null );
        }
    });
    Robot robot = new Robot();
    robot.delay( 10 );
    EventQueue.invokeAndWait(new Runnable() {
        @Override
        public void run() {
            // now passes
            assertTrue( app.mainFrame.searchDlg.inputJTF.hasFocus() );
        }
    });

...如果 robot.delay() 减为 1 或不存在,则失败发生。

显然这与实现 JDialog.

所需的有限时间有关

Rob Camick 的回答很有趣,RequestFocusListener 按预期工作。

然而,他的回答实际上并没有回答问题:这是:发生了什么,为什么这个测试失败了?