简体   繁体   English

关键侦听器和执行的操作

[英]Key listener and action performed

我正在使用GUI的动作侦听器,但是我想在某个按键上关闭我的应用程序时,是否可以在执行动作的方法中发生按键事件

You could use an AbstractAction, which is like an ActionListener on steroids, then assign it to your JButton as it's Action via the button's setAction(...) method. 您可以使用AbstractAction,类似于类固醇上的ActionListener,然后通过按钮的setAction(...)方法将其作为Action分配给JButton。 Then I would use Key Bindings , not a KeyListener as this will allow us to get around the KeyListener component focus issue with ease, and bind the very same AbstractAction to your key press using the key bindings. 然后,我将使用Key Bindings ,而不是KeyListener,因为这将使我们能够轻松解决KeyListener组件的焦点问题,并使用键绑定将完全相同的AbstractAction绑定到您的按键上。

Note that if you set the JButton's or the AbstractAction's mnemonic properly, then an alt-key combination will automatically work in pressing the button. 请注意,如果您正确设置了JButton或AbstractAction的助记符,则按下该按钮时,将自动使用alt键组合。

This one below may be over-kill for you, but it allows this same action to be used in Key Bindings, a JButton or a JMenuItem, which is a little tricky to do. 下面的这个可能对您来说太过致命了,但是它允许在按键绑定,JButton或JMenuItem中使用相同的操作,这有点棘手。

// class of mine to allow disposing of a window
// It's a little complex to allow it to work with either a JButton
// or a JMenuItem
@SuppressWarnings("serial")
class ExitAction extends AbstractAction {
    public ExitAction() {
        super("Exit");
        putValue(MNEMONIC_KEY, KeyEvent.VK_X);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // get the button that caused this action
        Object source = e.getSource();
        Window topWindow = null;
        if (source instanceof AbstractButton) {
            AbstractButton exitButton = (AbstractButton) source;

            // get the parent top level window
            topWindow = SwingUtilities.getWindowAncestor(exitButton);
            if (topWindow == null) { // if null, then likely in a JMenuItem
                // so we have to get its jpopupmenu parent
                Container parent = exitButton.getParent();
                if (parent instanceof JPopupMenu) {
                    JPopupMenu popupMenu = (JPopupMenu) parent;

                    // get the invoker for the pop up menu
                    Component invoker = popupMenu.getInvoker();
                    if (invoker != null) {
                        // and get *its* top level window
                        topWindow = SwingUtilities.getWindowAncestor(invoker);
                    }
                }
            }
        } else if (source instanceof Component) {
            // if in key bindings
            topWindow = SwingUtilities.getWindowAncestor((Component) source);
        }
        if (topWindow != null) {
            // dispose of the top-level window
            topWindow.dispose();
        }
    }
}

This is from a demo program that I created for another StackOverflow question . 这是我为另一个StackOverflow问题创建的演示程序。 Here's the code in its entirety. 这是完整的代码。 It also demonstrates use of CardLayout: 它还演示了CardLayout的用法:

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

/**
 * https://stackoverflow.com/questions/30288947
 * /accessing-jcombobox-data-from-separate-jform
 * 
 * @author Pete
 *
 */
public class SimpleMultPanels {
    private static void createAndShowGui() {
        // create JFrame
        JFrame frame = new JFrame("SimpleMultPanels");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        // add our MainPanel to the JFrame
        frame.getContentPane().add(new MainPanel());
        frame.pack(); // pack it
        frame.setLocationByPlatform(true);
        frame.setVisible(true); // show it
    }

    public static void main(String[] args) {
        // this is for starting our Swing app on the event thread
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

@SuppressWarnings("serial")
class MainPanel extends JPanel {
    private static final KeyStroke EXIT_KEY_STROKE = KeyStroke.getKeyStroke(
            KeyEvent.VK_Z, KeyEvent.CTRL_DOWN_MASK);;

    private CardLayout cardLayout = new CardLayout();

    // the three "card" JPanels that this JPanel displays:
    private MenuPanel menuPanel = new MenuPanel();
    private HoldsComboBoxPanel holdsComboBoxPanel = new HoldsComboBoxPanel();
    private ShowSelectionPanel showSelectionPanel = new ShowSelectionPanel();

    // Actions for our JButtons
    private ExitAction exitAction = new ExitAction();
    private ShowAction backToMenuAction = new ShowAction(this, "Back to Menu",
            MenuPanel.NAME, KeyEvent.VK_B);
    private ShowAction toHoldsComboAction = new ShowAction(this, "Combo Panel",
            HoldsComboBoxPanel.NAME, KeyEvent.VK_C);
    private ShowAction toShowSelectionAction = new ShowAction(this,
            "Show Selection", ShowSelectionPanel.NAME, KeyEvent.VK_S);

    public MainPanel() {
        // add an ActionListener to the JComboBox
        holdsComboBoxPanel.addComboBoxListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // get the combo's selected String
                String selection = holdsComboBoxPanel.getComboSelection();
                if (selection != null) {
                    // push it into showSelection
                    showSelectionPanel.setDisplayText(selection);
                }
            }
        });

        // add Actions to class to allow swapping of cards and
        holdsComboBoxPanel.addButtonAction(backToMenuAction);
        holdsComboBoxPanel.addButtonAction(toShowSelectionAction);
        holdsComboBoxPanel.addButtonAction(exitAction); // and to exit gui

        showSelectionPanel.addButtonAction(backToMenuAction);
        showSelectionPanel.addButtonAction(toHoldsComboAction);
        showSelectionPanel.addButtonAction(exitAction);

        menuPanel.addButtonAction(toHoldsComboAction);
        menuPanel.addButtonAction(toShowSelectionAction);
        menuPanel.addButtonAction(exitAction);

        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        // set our layout
        setLayout(cardLayout);

        // and add our "card" JPanels
        add(menuPanel, MenuPanel.NAME);
        add(holdsComboBoxPanel, HoldsComboBoxPanel.NAME);
        add(showSelectionPanel, ShowSelectionPanel.NAME);

        setExitOnKeyStroke(EXIT_KEY_STROKE); // added 9/27/15
    }

    private void setExitOnKeyStroke(KeyStroke keyStroke) {
        // do your key bindings

        // first get ActionMap and InputMap
        InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = getActionMap();

        // then the keystroke
        String key = keyStroke.toString();

        inputMap.put(keyStroke, key); // map the keystroke to a String key
        actionMap.put(key, exitAction); // map the same String key to the Action
    }

    // method that allows outside classes to swap views
    public void showCard(String key) {
        cardLayout.show(this, key);
    }
}

@SuppressWarnings("serial")
class HoldsComboBoxPanel extends JPanel {
    // constant String that will be used by the CardLayout
    public static final String NAME = "holds combobox panel";

    // sample data
    private static final String[] DATA = { "Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday" };
    private JComboBox<String> comboBox = new JComboBox<>(DATA);

    // JPanel to hold buttons to allow moving between cards
    private JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));

    public HoldsComboBoxPanel() {
        comboBox.setSelectedIndex(-1);
        JPanel centerPanel = new JPanel();
        centerPanel.add(comboBox);

        setLayout(new BorderLayout());
        add(centerPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    // method to add a listener
    public void addComboBoxListener(ActionListener listener) {
        comboBox.addActionListener(listener);
    }

    // getter method
    public String getComboSelection() {
        return (String) comboBox.getSelectedItem();
    }

    // create a new JButton with an Action and add to buttonPanel
    public void addButtonAction(Action action) {
        buttonPanel.add(new JButton(action));
    }
}

@SuppressWarnings("serial")
class ShowSelectionPanel extends JPanel {
    public static final String NAME = "show selection panel";
    private static final int PREF_W = 300;
    private static final int PREF_H = PREF_W;
    private JTextField displayField = new JTextField(10);
    private JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));

    public ShowSelectionPanel() {
        displayField.setFocusable(false);

        JPanel centerPanel = new JPanel();
        centerPanel.add(displayField);

        setLayout(new BorderLayout());
        add(centerPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    // code to make our GUI a little larger
    @Override
    public Dimension getPreferredSize() {
        Dimension superSz = super.getPreferredSize();
        if (isPreferredSizeSet()) {
            return superSz;
        }
        int prefW = Math.max(superSz.width, PREF_W);
        int prefH = Math.max(superSz.height, PREF_H);
        return new Dimension(prefW, prefH);
    }

    // setter method
    public void setDisplayText(String text) {
        displayField.setText(text);
        // or do whatever else you want to do with the selection
    }

    public void addButtonAction(Action action) {
        buttonPanel.add(new JButton(action));
    }

}

@SuppressWarnings("serial")
class MenuPanel extends JPanel {
    public static final String NAME = "menu panel";
    private JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 0, 5));

    public MenuPanel() {
        setLayout(new GridBagLayout());
        add(buttonPanel);
    }

    public void addButtonAction(Action action) {
        buttonPanel.add(new JButton(action));
    }
}

@SuppressWarnings("serial")
class ShowAction extends AbstractAction {
    private MainPanel mainPanel;
    private String key;

    /**
     * Abstract Action used by JButtons
     * 
     * @param mainPanel
     *            : the JPanel that uses the CardLayout
     * @param name
     *            : The name displayed by the button
     * @param key
     *            : The key used in the CardLayout#show(String key) mehtod
     * @param mnemonic
     *            : the JButton's mnemonic char
     */
    public ShowAction(MainPanel mainPanel, String name, String key, int mnemonic) {
        super(name);
        putValue(MNEMONIC_KEY, mnemonic);
        this.mainPanel = mainPanel;
        this.key = key;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // tell the mainPanel to show the card associated with the key
        mainPanel.showCard(key);
    }
}

// class of mine to allow disposing of a window
// It's a little complex to allow it to work with either a JButton
// or a JMenuItem
@SuppressWarnings("serial")
class ExitAction extends AbstractAction {
    public ExitAction() {
        super("Exit");
        putValue(MNEMONIC_KEY, KeyEvent.VK_X);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // get the button that caused this action
        Object source = e.getSource();
        Window topWindow = null;
        if (source instanceof AbstractButton) {
            AbstractButton exitButton = (AbstractButton) source;

            // get the parent top level window
            topWindow = SwingUtilities.getWindowAncestor(exitButton);
            if (topWindow == null) { // if null, then likely in a JMenuItem
                // so we have to get its jpopupmenu parent
                Container parent = exitButton.getParent();
                if (parent instanceof JPopupMenu) {
                    JPopupMenu popupMenu = (JPopupMenu) parent;

                    // get the invoker for the pop up menu
                    Component invoker = popupMenu.getInvoker();
                    if (invoker != null) {
                        // and get *its* top level window
                        topWindow = SwingUtilities.getWindowAncestor(invoker);
                    }
                }
            }
        } else if (source instanceof Component) {
            // if in key bindings
            topWindow = SwingUtilities.getWindowAncestor((Component) source);
        }
        if (topWindow != null) {
            // dispose of the top-level window
            topWindow.dispose();
        }
    }
}

If you add this method in the MainPanel class and call it in MainPanel's constructor, you'll bind the exit action to a keystroke of choice: 如果将此方法添加到MainPanel类中并在MainPanel的构造函数中调用它,则将exit操作绑定到所选的击键:

    private void setExitOnKeyStroke(KeyStroke keyStroke) {
        // do your key bindings

        // first get ActionMap and InputMap
        InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = getActionMap();

        // then the keystroke
        String key = keyStroke.toString();

        inputMap.put(keyStroke, key); // map the keystroke to a String key
        actionMap.put(key, exitAction); // map the same String key to the Action
    }

    // method that allows outside classes to swap views
    public void showCard(String key) {
        cardLayout.show(this, key);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM