简体   繁体   English

在Swing中为对话框设置最初关注的组件的正确方法是什么?

[英]What is the proper way to set initially focused component for a dialog in Swing?

I have a bug lurking where the focus is sporadically not ending up on the text field I want it on after popping up a JOptionPane containing the text field. 我有一个潜伏的错误,即在弹出包含文本字段的JOptionPane之后,焦点偶尔不会最终出现在想要的文本字段上。

I eventually boiled it down to a reasonable example: 我最终将其简化为一个合理的示例:

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

Attempted solutions #1 through #3 all fail to put the focus in the text field. 尝试的解决方案1至3都无法将焦点放在文本字段中。 Attempted solution #4 works but having to use three levels of nested SwingUtilities.invokeLater calls can't possibly be the proper way to do this. 尝试的解决方案4可行,但是必须使用三级嵌套的SwingUtilities.invokeLater调用可能不是执行此操作的正确方法。

So what is the proper way? 那么,什么正确的方法是什么?

I notice that JOptionPane.showInputDialog ' text field does receive focus, so clearly there is a way to do it. 我注意到JOptionPane.showInputDialog '文本字段确实获得了焦点,因此很明显有一种方法可以做到这一点。

I don't know the canonical solution, but you could try just one call to queue on the event thread within your window listener. 我不知道规范的解决方案,但是您可以尝试只进行一次调用以在窗口侦听器中的事件线程上排队。 For eg, 例如

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

Other possible "kludges" include using a short single-run Swing timer. 其他可能的“麻烦”包括使用短的单次运行Swing计时器。

Have you considered subclassing / initializing a JDialog directly instead of using JOptionPane ? 您是否考虑过直接子类化/初始化JDialog而不是使用JOptionPane?

The reason why java does not have a "setFocusInWindow" is because on some platforms it is not possible to directly "set" the focus (as much as request it. ) Java之所以没有“ setFocusInWindow”,是因为在某些平台上,无法直接“设置”焦点(尽可能多地请求焦点)。

To me it seems like the call to "setVisible()" is putting a event on the EDT, to make the window visible, which in turn is changing the focus away from your text field. 在我看来,对“ setVisible()”的调用似乎在EDT上放置了一个事件,以使窗口可见,这又将焦点从文本字段移开了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM