3

我创建了一个接收动作的 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);
        }
    }
}
4

2 回答 2

5

JButton当您可以简单地将KeyBindings 添加到其实例时,为什么要扩展类?

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

基本上 aJButton可以通过鼠标单击或按下F1(只要焦点在窗口中并且如果按下将焦点转移到JButton)或ENTER(仅当焦点位于JButton)来激活。

当被调用时AbstractAction,它将调用(因此按下将使按钮获得焦点,这是我认为你想要的):requestFocusInWindow()JButtonF1

在此处输入图像描述

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);
            }
        });
    }
}

更新:

或者,正如@GuillaumePolet 建议的那样(对他+1)覆盖processKeyBindingJButton检查适当的密钥,然后调用该方法:

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() {
                final JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                final JButton btn = new JButton("Button") {
                    @Override
                    protected boolean processKeyBinding(KeyStroke ks, KeyEvent ke, int i, boolean bln) {
                        boolean b = super.processKeyBinding(ks, ke, i, bln);

                        if (b && ks.getKeyCode() == KeyEvent.VK_F1) {
                            requestFocusInWindow();
                        }

                        return b;
                    }
                };

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

                //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);
            }
        });
    }
}
于 2012-11-26T13:40:48.523 回答
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();
            }
        });
    }

}
于 2012-11-26T14:09:49.543 回答