Альтернативный фокус между элементами JOptionPane

#java #swing #jtextfield #joptionpane

#java #качать #jtextfield #joptionpane

Вопрос:

Я пытаюсь показать a JOptionPane с a 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:

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

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

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

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

Пользовательское JTextField, которое не использует определенные нажатия клавиш. Это называется MultiplexingTextField и передает обработку нажатий клавиш, если для этого настроено:

 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 amp;amp; condition != JComponent.WHEN_IN_FOCUSED_WINDOW
                amp;amp; 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);
  

Комментарии:

1. большое спасибо за ваш ответ! 🙂 Я попробую и опубликую здесь. С уважением, Фелипе.