JOptionPane元素之间的交替关注

时间:2011-10-05 19:03:55

标签: java swing jtextfield joptionpane

我正在尝试向JOptionPane显示一个JTextField,其中有一个初始焦点,并且,当用户按下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"按钮。

我尝试过听众,但似乎我无法从内部访问非最终数据 - 即文本字段。

1 个答案:

答案 0 :(得分:4)

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

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

最后一个可以通过JTextField的自定义子类来解决,就像BasicOptionPaneUI用于inputDialog一样,它在最后显示 - 只有在解决前两个时才在optionPane上下文中使用。我没有看到一个完全令人满意的解决方案:将“消息”的概念与“选项”的概念混合,将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);