Запустите JButton с помощью пробела, или введите клавишу, или щелкните мышью

Я пытаюсь получить простой JFrame с одной кнопкой для запуска события, когда происходит любое из этих событий:

  • Клавиша Enter нажата И кнопка J имеет фокус
  • Пробел нажимается И JButton имеет фокус
  • JButton нажата.

Кажется, что Enter и пробел приходят "бесплатно" вместе с щелчком мыши по умолчанию, используя addActionListener на JButton; Беда в том, что я читал, что привязки клавиш зависят от использованного стиля Look and Feel.

Я попытался добиться универсального поведения в LaF, добавив Enter и пробел к карте действий JButton, и даже добавил случайный ключ ("m"), чтобы убедиться, что ActionMap выполняет свою работу (она была), но теперь мышь клик потерян. Мне кажется, что единственный способ получить все ключи и щелчок мышью - это использовать как карту действий, так и addActionListener.

Есть ли способ заставить эти привязки клавиш и мыши работать согласованно на всем LaF, не пытаясь обнаружить все возможные LaF, которые могут возникнуть? Могу ли я зарегистрировать прослушиватель с одним действием, который будет вызывать события, связанные с клавишами и мышью?

Моим любимым решением было бы добавить щелчок мыши на карту действий JButton и определить, какая клавиша или щелчок мыши произошли внутри действия.

Я все еще изучаю веревки здесь, так что это, вероятно, не самый лучший или самый эффективный способ сделать что-то; Я уверен, что это чрезмерно спроектировано. Это своего рода тренировочное упражнение, в котором я экспериментирую со всем, что у меня есть. Любые комментарии в стиле кодирования приветствуются!

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

public class Example extends JFrame {

// ============================
private class BtnListener extends AbstractAction {
    private static final long serialVersionUID = 1L;

    public void actionPerformed(ActionEvent ae) {
        System.out.println("\nclick button listener triggered");
        System.out.println(ae.getSource().getClass().toString());
    }
} // class BtnListener

private static final int NO_MODIFIER = 0;
private static final boolean ON_KEY_PRESS = false;
private static final KeyStroke ENTER_PRESSED = KeyStroke.getKeyStroke(
        KeyEvent.VK_ENTER, NO_MODIFIER, ON_KEY_PRESS);
private static final KeyStroke M_PRESSED = KeyStroke.getKeyStroke(
        KeyEvent.VK_M, NO_MODIFIER, ON_KEY_PRESS);
private static final KeyStroke SPACEBAR_PRESSED = KeyStroke.getKeyStroke(
        KeyEvent.VK_SPACE, NO_MODIFIER, ON_KEY_PRESS);
private JButton btnButton;
private final AbstractAction btnListener = new BtnListener();
private JPanel buttonPanel;
private JFrame frmMain;

public static void main(String[] args) {
    Example ex = new Example();
    ex.displayFrame();
}

Action btnActionListener = new AbstractAction() {
    private static final long serialVersionUID = 1L;

    public void actionPerformed(ActionEvent e) {
        System.out.println("\nkey button action triggerred");
        System.out.println(e.getSource().getClass().toString());
        if (e.getSource() instanceof JButton) {
            System.out.println("button");
        } else {
            System.out.println("Something else");
        }
    }
};

public Example() {
    initialize();
}

public void displayFrame() {
    try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (Throwable e) {
        e.printStackTrace();
    }
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                frmMain.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

private void initialize() {

    frmMain = new JFrame();
    btnButton = new JButton("Abutton");

    // Comment this out, you lose the mouse click
    btnButton.addActionListener(btnListener);

    // Comment out ActionMaps, but keep addActionListner (above), and
            // only lose M_PRESSED
    InputMap buttonFocusedMap = btnButton
            .getInputMap(JComponent.WHEN_FOCUSED);

    buttonFocusedMap.put(ENTER_PRESSED, "blah");
    btnButton.getActionMap().put("blah", btnActionListener);

    buttonFocusedMap.put(SPACEBAR_PRESSED, "blort");
    btnButton.getActionMap().put("blort", btnActionListener);

    buttonFocusedMap.put(M_PRESSED, "gaaak");
    btnButton.getActionMap().put("gaaak", btnActionListener);

    // Is there a way to add a mouse click to the ActionMap?

    buttonPanel = new JPanel();
    buttonPanel.add(btnButton);

    frmMain.getContentPane().add(buttonPanel);
    frmMain.setBounds(100, 100, 500, 432);
    frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

}

2 ответа

Решение

BasicButtonListener, использован BasicButtonUI, гарантирует, что все кнопки (галочка, радио, переключатель) привязаны к пробелу при фокусировке. Это работает на разных платформах, даже если отдельные стили Look & Feels могут отображать различные состояния модели кнопок однозначно. Нажатие пробела вызывает нажатие UIAction и освобождение Космоса вызывает освобожденный UIAction, То же самое происходит, когда мышь нажимают и отпускают в пределах кнопки; потяните за кнопку, чтобы увидеть изменение режима охраны.

В любом случае комбинация нажатых и отпущенных вызывает ваши кнопки actionPerformed() метод.

Один из удобных способов привязать Enter к Action независимо от фокуса, через корневую панель setDefaultButton() метод. Этот пример иллюстрирует все три способа нажатия кнопки.

Что вы можете (и, вероятно, должны) сделать, это создать AbstractAction. Вы можете использовать AbstractAction как для ActionMap, так и для нажатия (сделайте JButton.setAction(...))

Другие вопросы по тегам