Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Swing中为对话框设置初始焦点组件的正确方法是什么?_Java_Swing_Focus_Joptionpane - Fatal编程技术网

Java 在Swing中为对话框设置初始焦点组件的正确方法是什么?

Java 在Swing中为对话框设置初始焦点组件的正确方法是什么?,java,swing,focus,joptionpane,Java,Swing,Focus,Joptionpane,在弹出包含文本字段的JOptionPane后,我发现一个bug潜伏在焦点偶尔不会出现在我想要的文本字段上 我最终把它归结为一个合理的例子: import javax.swing.BorderFactory; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingUtil

在弹出包含文本字段的
JOptionPane
后,我发现一个bug潜伏在焦点偶尔不会出现在我想要的文本字段上

我最终把它归结为一个合理的例子:

import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Component;

public class FocusIssueTest {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                // The real thing has many more components in there,
                // but I removed them for the demo.
                MyInputPane myInputPane = new MyInputPane();
                myInputPane.showDialog(null);
            }
        });
    }

    public static class MyInputPane extends JPanel {
        private final JTextField textField;

        protected MyInputPane() {
            textField = new JTextField();
            textField.selectAll();
            textField.setColumns(30);

            setLayout(new BorderLayout());
            add(textField, BorderLayout.CENTER);
        }

        public boolean showDialog(Component parentComponent) {

            final JOptionPane optionPane = new JOptionPane(
                this, JOptionPane.PLAIN_MESSAGE,
                JOptionPane.OK_CANCEL_OPTION);

            JDialog dialog = optionPane.createDialog(
                parentComponent, "Select a Thing");

            /* Attempted solution #1 - wait until the window is active
            dialog.addWindowListener(new WindowAdapter() {
                @Override
                public void windowActivated(WindowEvent event) {
                    textField.requestFocusInWindow();
                }
            });
            */

            /* Attempted solution #2 - camickr's RequestFocusListener
            textField.addAncestorListener(new AncestorListener() {
                @Override
                public void ancestorAdded(AncestorEvent event) {
                    JComponent component = event.getComponent();
                    component.requestFocusInWindow();
                    component.removeAncestorListener(this);
                }

                @Override
                public void ancestorRemoved(AncestorEvent event) {

                }

                @Override
                public void ancestorMoved(AncestorEvent event) {

                }
            });
            */

            /* Attempted solution #3 - HierarchyListener
            textField.addHierarchyListener(new HierarchyListener() {
                @Override
                public void hierarchyChanged(HierarchyEvent event) {
                    Component component = event.getComponent();
                    if ((HierarchyEvent.SHOWING_CHANGED &
                         event.getChangeFlags()) != 0 &&
                            component.isShowing()) {
                        component.requestFocusInWindow();
                        component.removeHierarchyListener(this);
                    }
                }
            });
            */

            // Attempted solution #4 - appears to work but can't be
            // right, because eww.
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            SwingUtilities.invokeLater(new Runnable() {
                                @Override
                                public void run() {
                                    textField.requestFocusInWindow();
                                }
                            });
                        }
                    });
                }
            });

            dialog.setVisible(true);
            Object selectedValue = optionPane.getValue();
            return selectedValue instanceof Integer &&
                   (int) selectedValue == 0;
        }
    }
}
尝试的解决方案#1到#3都未能将焦点放在文本字段中。尝试的解决方案#4可以工作,但必须使用三级嵌套的
SwingUtilities。调用器
调用不可能是正确的方法

那么正确的方法是什么呢


我注意到,
JOptionPane.showInputDialog
”文本字段确实接收焦点,因此显然有一种方法可以做到这一点。

我不知道规范解决方案,但您可以尝试在窗口侦听器内的事件线程上调用一次队列。例如

     dialog.addWindowListener(new WindowAdapter() {
        @Override
        public void windowActivated(WindowEvent event) {
           SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                 textField.requestFocusInWindow();
              }
           });
        }
     });

其他可能的“麻烦”包括使用短的单次运行Swing计时器。

您是否考虑过直接子类化/初始化JDialog而不是使用JOptionPane

java没有“setFocusInWindow”的原因是,在某些平台上,不可能直接“设置”焦点(只要请求就可以)


对我来说,调用“setVisible()”似乎是在EDT上放置一个事件,使窗口可见,这反过来又改变了文本字段的焦点

一个肯定不行。两个人大部分时间都在工作,但似乎是随机选择不工作。三个看起来相当可靠,但我的意思是,我怎么能保证它是好的?也许它失败的次数更少,但仍然失败。:)@Trejkaz:考虑查看<代码> joptPANE.StutnPutualCudio的源代码,看看Swing编码器是如何做到的。顺便提一下,你的问题问得很好。看起来他们在BasicOptions Paneui中维护了一个名为inputComponent的字段。如果该字段为非空,则在显示对话框之前将聚焦该字段。如果WantInput被设置为true,他们会设置它,但是没有其他方法来设置我自己的值(不过反射可能会工作,并且在一种不好的方式下有点诱人。)@camickr非常有趣,我已经考虑过了,但是JOptionPane包含很多rtl布局的代码,我倾向于远离JOptionPane,因为它使编写单元测试在模拟用户输入响应时变得更加困难。设置对话框上的可见块,sun会在对话框处于活动状态时(如果是模态的话)创建一个新的EDT来处理事件。苏。。。。创建componentListener并覆盖文本字段的“ComponentResistized”方法(在调用setVisible(true)后调用该方法)。由optionPane创建的对话框有自己的windowListener,该方法会敲打JOptionPane.initDialog()中定义的焦点(你说得对,这是单元测试的一个难题。在工作中,我通过抽象询问信息的行为来解决这个特定问题。因此,代码从不直接显示选项窗格,它总是类似于selectThingDisplayer.ask(),这很容易在测试中模拟出来。这还意味着,如果我以后确实必须从选项窗格切换,我不必更改调用…这类似于我的消息对话框和用户确认方法(有一个单独的类包装JOptionPane,然后在测试用例中使用DI覆盖它)