当后者变得可见时,将焦点放在JDialog中的JTextField上

时间:2016-05-05 17:43:56

标签: java swing focus jdialog

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

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

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

事实上,当我显示JDialog时,焦点在JTF上...但后者恰好也是JDialog中的“第一个”组件(NORTH面板),所以这并不奇怪

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

    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 );

        }
    });

...所以实际上我被告知“焦点所有者”为空......而且JTF没有焦点。谁能解释一下发生了什么?

2 个答案:

答案 0 :(得分:3)

大多数对话框都是模态的,这意味着在关闭对话框之前,不会执行setVisible(true)语句之后的语句。

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

如果由于某种原因您需要专注于不同的组件,请查看Dialog Focus以获得一个解决方案,以便您控制哪个组件得到关注。

一旦组件显示在可见的对话框/框架上,此解决方案使用AncestorListener将焦点放在组件上。

答案 1 :(得分:0)

Aha ...这是JUnit和Java GUI的“Gotcha”之一。

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

    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所需的有限时间有关。

罗布·卡米克的回答很有趣,RequestFocusListener按预期工作。

然而,他的答案实际上并没有回答这个问题:这是怎么回事?为什么这个测试会失败?