【问题标题】:JButton & Action & KeyBindingJButton & Action & KeyBinding
【发布时间】:2012-11-26 13:32:39
【问题描述】:

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

【问题讨论】:

  • 有什么理由不打电话给super.setAction
  • 不,以您的方式调用它没有问题,按钮工作正常,但是当按下 F1 键时,动作完成但焦点永远不会转到按钮。我需要做的是在执行操作时使按钮聚焦并按下。
  • 为了尽快获得更好的帮助,请发布SSCCE(此示例至少需要main(String[]) 才能在选项窗格中的屏幕上显示IButtonSave)。
  • IButtonSave 是我在每个新对话框或框架中调用的类,我需要将操作保存到数据库。
  • 更多细节,例如,如果用户按下 F1,则按钮变为红色,但我需要在调用操作时在操作侧执行此操作。

标签: java swing focus jbutton key-bindings


【解决方案1】:

既然可以简单地将KeyBindings 添加到其实例中,为什么还要扩展JButton 类?

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

基本上是一个JButton,可以通过鼠标点击激活,或者按下F1(只要焦点在窗口中并且如果按下就会将焦点转移到JButton)或者ENTER (仅当在JButton 的焦点上时)。

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

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)覆盖JButtonprocessKeyBinding 并检查适当的键,然后调用该方法:

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

【讨论】:

  • 助记符必须与 L&F 无鼠标修饰符(通常是 Alt 键)结合使用。另外,Action 可以直接在 JButton 上设置,而不是手动处理所有这些或使用 ActionListener
  • 100% 正确,但如果按 F1,按钮将无法聚焦
  • @Motasem 因为如果你想让这种情况发生,它不应该只是在按钮实例上调用requestFocusInWindow()
【解决方案2】:

不确定这是不是最好的方法,但它工作得很好,如果它不是最好的方法,你可以从这个答案中得到一个免费的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();
            }
        });
    }

}

【讨论】:

  • Thaaaaaaaaaanks,这真的很有帮助,我不知道该怎么感谢你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多