开发者

Alternate focus between elements of JOptionPane

开发者 https://www.devze.com 2023-04-10 18:07 出处:网络
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 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.showOptionDi开发者_JAVA技巧alog(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.


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);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号