Альтернативный фокус между элементами JOptionPane - PullRequest
3 голосов
/ 05 октября 2011

Я пытаюсь показать 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 Ответ

4 голосов
/ 06 октября 2011

В принципе, у вас есть несколько проблем, которые борются друг с другом, чтобы их решить :-)

  • изначально сфокусированный компонент: использовать метод createOptionDialog для передачи нескольких пользовательских компонентов в поле сообщения, а начальный - как initialSelectionValue, немного хитро.
  • настраиваемые кнопки: опять-таки это небольшая хитрость, чтобы передать пользовательский текст (или реальные кнопки, на самом деле не имеет значения) в качестве параметра параметров. Фактически, это должен быть выбор, доступный пользователю, один из которых является изначально выбранным (который затем получает фокус)
  • действие над текстовым полем и первая кнопка (== кнопка по умолчанию во вложенной корневой панели): здесь само поле стоит так, чтобы разрешить и то и другое, так как оно съедает клавишу ввода

последнее может быть решено с помощью пользовательского подкласса JTextField, точно так же, как BasicOptionPaneUI использует для inputDialog, это показано в конце - полезно в контексте optionPane, только если первые два решены. Для которого я не нашел полностью удовлетворительного решения: смешивание понятия «сообщение» с понятием «параметры» путает optionPane с , а не установкой кнопки по умолчанию для корневой панели. Поэтому, в конце концов, вам может быть лучше не использовать этот первый трюк, придерживайтесь понятия «опции», а затем обманывайте фокус, запрашивая передачу в поле addNotify.

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

Пользовательский JTextField, который не использует определенные нажатия клавиш. Он называется 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);
...