JOptionPane 元素之间的交替焦点

发布于 2024-12-08 00:50:39 字数 771 浏览 4 评论 0原文

我试图显示一个带有 JTextFieldJOptionPane,它具有初始焦点,并且一旦用户按下 ENTER,我希望它执行一个操作在文本字段中输入的文本。

我做了一些广泛的搜索,但没有找到任何可以帮助我的东西。我将在这里说明到目前为止我所管理的内容:

这就是我所得到的,

Object[] options = {"Option1",
"Option2"};

Object[] message = new Object[2];

message[0] = "Type in the number of the incident:";
JTextField incidentNumberTextField = new JTextField();
message[1] = incidentNumberTextField;

int n = JOptionPane.showOptionDialog(frame,
    message,
    "Open incident",
    JOptionPane.YES_NO_OPTION,
    JOptionPane.QUESTION_MESSAGE,
    null,
    options,
    message[1]);
if (n == -1) {
    return;
}

到目前为止它运行良好。当对话框出现时,焦点位于文本字段上。但是,当我输入文本并按 Enter 时,它希望它自动触发“Option1”按钮。

我已经尝试过侦听器,但似乎我无法从其中访问非最终数据(即文本字段)。

I am trying to show a JOptionPane with a JTextField, which has initial focus, in it and, as soon as the user press ENTER, I want it to perform an action with the text entered in the text field.

I did some extensive search and I failed to find anything that could help me on that. I will state here what I managed so far:

This is what I got

Object[] options = {"Option1",
"Option2"};

Object[] message = new Object[2];

message[0] = "Type in the number of the incident:";
JTextField incidentNumberTextField = new JTextField();
message[1] = incidentNumberTextField;

int n = JOptionPane.showOptionDialog(frame,
    message,
    "Open incident",
    JOptionPane.YES_NO_OPTION,
    JOptionPane.QUESTION_MESSAGE,
    null,
    options,
    message[1]);
if (n == -1) {
    return;
}

It works fine so far. When the dialog shows up, the focus is on the text field. However, when I type in the text and press Enter, it would like it to automatically trigger the "Option1" button.

I have tried listeners, but it seems I can not access data that is not final - i.e. the text field - from inside it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

南城旧梦 2024-12-15 00:50:39

基本上,您有几个问题需要相互斗争来解决:-)

  • 最初集中的组件:使用 createOptionDialog 方法在消息字段中传递多个自定义组件并将初始值作为“initialSelectionValue”是一个技巧。
  • 自定义按钮:再次将自定义文本(或真正的按钮,并不重要)作为选项参数传递是一个技巧。实际上,它是用户可用的选择,其中一个是
  • 文本字段上最初选择的(然后获得焦点)操作第一个按钮(==默认按钮)封闭根窗格):这里字段本身阻碍了两者的实现,因为它占用了回车键,

最后一个可以通过 JTextField 的自定义子类来解决,就像 BasicOptionPaneUI 用于 inputDialog 一样,它显示在最后 - 有用选项面板仅当前两个问题得到解决时,上下文才有效。我还没有看到完全令人满意的解决方案:将“消息”的概念与“选项”的概念混合在一起会使 optionPane 混淆,设置 rootpane 的默认按钮。因此,最后,您可能最好不要使用第一个技巧,坚持使用“选项”概念,然后通过在字段的 addNotify 中请求转移来欺骗焦点。

    @Override
    public void addNotify() {
        super.addNotify();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                requestFocus();
            }
        });                
    }

自定义 JTextField 不占用某些 keyStrokes。它称为 MultiplexingTextField,并传递 keyStrokes 的处理(如果配置为这样做):

public static class MultiplexingTextField extends JTextField {
    private List<KeyStroke> strokes;
    public MultiplexingTextField(int cols) {
        super(cols);
    }

    /**
     * Sets the KeyStrokes that will be additionally processed for
     * ancestor bindings.
     */
    public void addKeyStrokes(KeyStroke... keyStrokes) {
        for (KeyStroke keyStroke : keyStrokes) {
            getMultiplexingStrokes().add(keyStroke);
        }
    }

    private List<KeyStroke> getMultiplexingStrokes() {
        if (strokes == null) {
            strokes = new ArrayList<KeyStroke>();
        }
        return strokes;
    }

    @Override
    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
                                        int condition, boolean pressed) {
        boolean processed = super.processKeyBinding(ks, e, condition,
                                                    pressed);

        if (processed && condition != JComponent.WHEN_IN_FOCUSED_WINDOW
                && getMultiplexingStrokes().contains(ks)) {
            // Returning false will allow further processing
            // of the bindings, eg our parent Containers will get a
            // crack at them.
            return false;
        }
        return processed;
    }
}

在受控环境中使用:

    Action fieldAction = new AbstractAction("fieldAction") {

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("hello " + ((JTextComponent) e.getSource()).getText());
        }
    };
    JTextField field = new JTextField("this is a normal field");
    MultiplexingTextField multiplexing = new MultiplexingTextField(20);
    multiplexing.addKeyStrokes(KeyStroke.getKeyStroke("ENTER"));
    field.setAction(fieldAction);
    multiplexing.setAction(fieldAction);
    Action action = new AbstractAction("default button action") {

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("hello - got default button");
        }
    };
    JButton button = new JButton(action);
    JPanel panel = new JPanel();
    panel.add(field);
    panel.add(multiplexing);
    panel.add(button);
    // this is swingx testing support, simply replace with normal frame creation
    JXFrame frame = wrapInFrame(panel, "multiplex");
    frame.getRootPane().setDefaultButton(button);

Basically, you have several problems which are fighting with each other to get solved :-)

  • initially focused component: it's a bit of a trick to use the createOptionDialog method for passing in several custom components in the message field and the initial as "initialSelectionValue".
  • custom buttons: again it's a bit of a trick to pass in the custom text (or real buttons, doesn't really matter) as the options parameter. Actually, it is meant to be the choices available to the user, one of them being the initially selected (which then gets the focus)
  • action on the textfield and the first button (== default button in the enclosing rootpane): here the field itself stands in the way of allowing both, as it eats the enter key

the last can be solved by a custom subclass of JTextField, just as BasicOptionPaneUI uses for the inputDialog, it's shown at the end - useful in the optionPane context only if the first two are solved. Which I haven't seen a fully satisfactory solution for: mixing the concept of "message" with the concept of "options" confuses the optionPane into not setting the rootpane's default button. So at the end, you might be better of to not use that first trick, stick with the "options" notion and then tricks the focus via requesting a transfer in the field's addNotify.

    @Override
    public void addNotify() {
        super.addNotify();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                requestFocus();
            }
        });                
    }

The custom JTextField which doesn't eat certain keyStrokes. It's called MultiplexingTextField and passes on processing of keyStrokes if configured to do so:

public static class MultiplexingTextField extends JTextField {
    private List<KeyStroke> strokes;
    public MultiplexingTextField(int cols) {
        super(cols);
    }

    /**
     * Sets the KeyStrokes that will be additionally processed for
     * ancestor bindings.
     */
    public void addKeyStrokes(KeyStroke... keyStrokes) {
        for (KeyStroke keyStroke : keyStrokes) {
            getMultiplexingStrokes().add(keyStroke);
        }
    }

    private List<KeyStroke> getMultiplexingStrokes() {
        if (strokes == null) {
            strokes = new ArrayList<KeyStroke>();
        }
        return strokes;
    }

    @Override
    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
                                        int condition, boolean pressed) {
        boolean processed = super.processKeyBinding(ks, e, condition,
                                                    pressed);

        if (processed && condition != JComponent.WHEN_IN_FOCUSED_WINDOW
                && getMultiplexingStrokes().contains(ks)) {
            // Returning false will allow further processing
            // of the bindings, eg our parent Containers will get a
            // crack at them.
            return false;
        }
        return processed;
    }
}

usage in controlled environment:

    Action fieldAction = new AbstractAction("fieldAction") {

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("hello " + ((JTextComponent) e.getSource()).getText());
        }
    };
    JTextField field = new JTextField("this is a normal field");
    MultiplexingTextField multiplexing = new MultiplexingTextField(20);
    multiplexing.addKeyStrokes(KeyStroke.getKeyStroke("ENTER"));
    field.setAction(fieldAction);
    multiplexing.setAction(fieldAction);
    Action action = new AbstractAction("default button action") {

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("hello - got default button");
        }
    };
    JButton button = new JButton(action);
    JPanel panel = new JPanel();
    panel.add(field);
    panel.add(multiplexing);
    panel.add(button);
    // this is swingx testing support, simply replace with normal frame creation
    JXFrame frame = wrapInFrame(panel, "multiplex");
    frame.getRootPane().setDefaultButton(button);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文