繁体   English   中英

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

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

我有一个潜伏的错误,即在弹出包含文本字段的JOptionPane之后,焦点偶尔不会最终出现在想要的文本字段上。

我最终将其简化为一个合理的示例:

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.invokeLater调用可能不是执行此操作的正确方法。

那么,什么正确的方法是什么?

我注意到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上放置了一个事件,以使窗口可见,这又将焦点从文本字段移开了。

暂无
暂无

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

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