JButton&行动&键绑定

时间:2012-11-26 13:32:40

标签: java swing focus jbutton key-bindings

我创建了一个接收Action的JButton类,JButton类包括击键和&鼠标监听器,所以我可以根据需要在多个帧中使用相同的类。

我的问题是: 按下键时JButton没有获得焦点,但它正在执行操作。 我需要创建一个新的背景或告诉用户该按钮执行操作的东西。

任何想法??

这是我的代码:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;
import swtdesigner.SwingResourceManager;

public class IButtonSave extends JButton{
    private static final long serialVersionUID = 1L;
    private Action action = null;
    public IButtonSave() {
        super();
        setFocusPainted(true);
        setFocusable(true);

        try {
            jbInit();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private void jbInit() throws Exception {
        setMargin(new Insets(0, 0, 0, 0));
        setBorder(new LineBorder(Color.black, 1, true));
        setIconTextGap(0);
        setHorizontalTextPosition(SwingConstants.CENTER);
        setVerticalTextPosition(SwingConstants.TOP);
        setPreferredSize(new Dimension(50, 43));
        setMinimumSize(new Dimension(50, 43));
        setMaximumSize(new Dimension(50, 43));
        addMouseListener(new ThisMouseListener());
        setVerifyInputWhenFocusTarget(true);
    }

    public void setAction(Action a){
        action = a;
        KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F1,0,true);
        KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0);
        getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "Save");
        getInputMap(JComponent.WHEN_FOCUSED).put(ks2, "Save");

        getActionMap().put("Save", a);
        setText("Save [F1]");
        setIcon(SwingResourceManager.getIcon(SwingResourceManager.class, "/images/small/save.png"));
        setToolTipText("[F1]");
    }

    private class ThisMouseListener extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            this_mouseClicked(e);
        }
    }
    protected void this_mouseClicked(MouseEvent e) {
        if(e.getClickCount() >= 1){
            action.actionPerformed(null);
        }
    }
}

2 个答案:

答案 0 :(得分:5)

为什么只要将JButton添加到其实例中,就可以扩展KeyBinding类?

不确定你想要什么,但这对我来说很好:

基本上可以通过鼠标点击激活JButton,或按 F1 (只要焦点在窗口中,如果按下则将焦点转移到JButton)或 ENTER (仅在JButton焦点时)。

AbstractAction被调用时,它将在requestFocusInWindow()上调用JButton(因此按 F1 会使按钮获得焦点,这是我认为你想要的) :

enter image description here

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                final JButton btn = new JButton("Button");

                AbstractAction aa = new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        System.out.println("Here");

                        btn.requestFocusInWindow();//request that the button has focus
                    }
                };

                //so button can be pressed using F1 and ENTER
                btn.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
                btn.getActionMap().put("Enter", aa);
                btn.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "F1");
                btn.getActionMap().put("F1", aa);

                btn.addActionListener(aa);//so button can be clicked

                JTextField tf = new JTextField("added to show ENTER wont work unless button in focus");

                frame.add(tf);
                frame.add(btn, BorderLayout.SOUTH);

                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

<强> UPADTE:

或者@GuillaumePolet建议(+1给他)覆盖processKeyBinding的{​​{1}}并检查适当的密钥而不是调用方法:

JButton

答案 1 :(得分:3)

不确定这是做到这一点的最佳方式,但它运作得相当不错,如果不是最好的方式,你可以从这个答案中获得免费的SSCCE

我重写了processKeyBindings(),如果它返回true,那么我抓住焦点指示已经执行了该动作。如果你想做别的事,你只需要在那里修改代码。

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

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class IButtonSave extends JButton {
    private static final long serialVersionUID = 1L;

    public IButtonSave() {
        super();
        setFocusPainted(true);
        setFocusable(true);
    }

    @Override
    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
        boolean processKeyBinding = super.processKeyBinding(ks, e, condition, pressed);
        if (processKeyBinding) {
            requestFocusInWindow();
        }
        return processKeyBinding;
    }

    @Override
    public void setAction(Action a) {
        super.setAction(a);
        KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, true);
        KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
        getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "Save");
        getInputMap(JComponent.WHEN_FOCUSED).put(ks2, "Save");
        getActionMap().put("Save", a);
        setText("Save [F1]");
        setToolTipText("[F1]");
    }

    protected void initUI() {
        JFrame frame = new JFrame(IButtonSave.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTextArea textarea = new JTextArea(5, 30);
        JPanel buttonPanel = new JPanel();
        AbstractAction someAction = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.err.println("Action performed");
            }
        };
        IButtonSave button = new IButtonSave();
        button.setAction(someAction);
        buttonPanel.add(button);
        frame.add(new JScrollPane(textarea));
        frame.add(buttonPanel, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new IButtonSave().initUI();
            }
        });
    }

}