【问题标题】:How to set the Java default button to react on ENTER key _released_?如何设置 Java 默认按钮以对 ENTER 键 _released_ 做出反应?
【发布时间】:2012-08-28 23:08:34
【问题描述】:

在我的应用程序中,我使用默认按钮。我希望它在ENTER 密钥发布时做出反应。当ENTER 键被按下时不会。

我从按钮的InputMap 中删除了KeyStroke。但这对我不起作用。我该怎么做?


import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;

public class ButtonTest {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                buildFrame();
            }
        });
    }

    private static void buildFrame() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JButton button = new JButton(new AbstractAction("Button") {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("ButtonTest::actionPerformed: CALLED");
            }
        });

        JButton button2 = new JButton("Button 2");
        InputMap im = button.getInputMap();
        im.put(KeyStroke.getKeyStroke("ENTER"), "none");
        im.put(KeyStroke.getKeyStroke("released ENTER"), "released");

        f.setLayout(new GridBagLayout());
        f.add(button);
        f.add(button2);
        f.getRootPane().setDefaultButton(button);

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

这是示例代码。

【问题讨论】:

  • 发布部分代码...我可以轻松获得您的解决方案...
  • KeyReleased 和 KeyPressed 有什么区别,因为这个 JButton 必须从键盘接收一次 ENTER KeyEvent,你的意思是重复触发相同的动作直到 ENTER ... ???,
  • 在我按下触发“搜索”按钮的 Textfiled 上的 Enter 后,将显示在我的应用程序对话框中。如果我长时间按住 ENTER 键,则显示的对话框会自动关闭。因为它有默认按钮。
  • 你想防止来自ENTER的多人游戏事件(在你的情况下)??? ENTER 键的动作应该只触发一次???,新动作应该只在下一个 keyPressed 时触发???

标签: java swing event-handling defaultbutton


【解决方案1】:
    InputMap im = button.getInputMap();
    im.put(KeyStroke.getKeyStroke("ENTER"), "pressed");
    im.put(KeyStroke.getKeyStroke("released ENTER"), "released");

这样做的效果是按钮只执行一次 actionPerformed,当 ENTER 被释放时(如果我理解正确,这就是你想要的)。

编辑:运行的以下代码表明 actionPerformed 仅在 ENTER 释放时执行(尽管在视觉上该按钮似乎在 ENTER 按下时已按下)

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;

public class ButtonTest {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                buildFrame();
            }
        });
    }

    private static void buildFrame() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JButton button = new JButton(new AbstractAction("Button") {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("ButtonTest::actionPerformed: CALLED");
            }
        });

        InputMap im = button.getInputMap();
        im.put(KeyStroke.getKeyStroke("ENTER"), "pressed");
        im.put(KeyStroke.getKeyStroke("released ENTER"), "released");

        f.add(button);
        f.getRootPane().setDefaultButton(button);

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

【讨论】:

  • 我希望默认按钮仅在 Enter 键释放时做出反应。它不应该对 Enter 按键做出反应。
  • “反应”是什么意思?我添加了一个完整的运行示例,您可以在其中看到 actionPerformed 仅在 ENTER 释放时执行(尽管在视觉上按钮似乎在 ENTER 按下时已经按下)
  • "React" 表示触发按钮。默认按钮应仅在 Enter 释放时触发。 Enter Pressed 上什么都不会发生。
  • 在您的示例中,默认按钮触发 Enter Key Pressed.... 我通过按住 Enter 键一段时间来检查它,然后它连续打印出 Sys。
  • 按住 Enter 对我来说不会向系统打印任何内容,只有当我释放时...我不知道为什么它不适合你。
【解决方案2】:

您可以使用getKeyStroke() 的版本,它可以让您将onKeyRelease 设置为true,就像在这个answer 中一样

编辑:您可以停止重复,例如 answer

【讨论】:

  • 在 Swing Action 中使用内置布尔值,如@kleopatra 所示的代码
  • @mKorbel 谢谢!我添加了指向该答案的链接。
【解决方案3】:

默认按钮(即进入时触发的按钮,无论哪个组件是focusOwner)的键都绑定在rootPane的componentInputMap中,即其WHEN_IN_FOCUSED_WINDOW类型的inputMap。所以从技术上讲,这是需要调整的地方:

JComponent content = new JPanel();
content.add(new JTextField("some focusable"));
content.add(new JTextField("something else"));

JXFrame frame = wrapInFrame(content, "default button on released");
Action action = new AbstractAction("do something") {

    @Override
    public void actionPerformed(ActionEvent e) {
        LOG.info("clicked");
    }
};
JButton button = new JButton(action);
content.add(button);
frame.getRootPane().setDefaultButton(button);
// remove the binding for pressed
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
    .put(KeyStroke.getKeyStroke("ENTER"), "none");
// retarget the binding for released
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
    .put(KeyStroke.getKeyStroke("released ENTER"), "press");

注意:这与非默认按钮的按下/释放行为仍然不同,因为 rootPane 操作只是调用 button.doClick 而不通过武装/按下 buttonModel 的动作来间接触发操作。

【讨论】:

    【解决方案4】:
    JRootPane rootPane = SwingUtilities.getRootPane(/* Your JButton  */); 
    rootPane.setDefaultButton(/* Your JButton  */);
    

    【讨论】:

    • 你的代码给了我NPE,而这工作-JRootPane rootPane = SwingUtilities.getRootPane(/* Your JFrame */);
    • @raghavsood33 SwingUtilities.getRootPane(yourJButton); 只有在调用yourJFrame.add(yourJButton) 的效果后才能在没有 NPE 的情况下工作。在将按钮添加到框架(或已添加到框架的容器)之前,按钮显然没有根窗格。
    • 这对我不起作用。我逃脱了 NPE (NullPointerException),但按钮没有焦点或任何东西。
    • 更新:我在 .revalidate() 和 .repaint() 之前调用了 rootPane.setDefaultButton(btn) 方法。这就是问题所在。它现在工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-23
    • 2023-03-14
    • 2019-11-23
    • 2018-11-02
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    相关资源
    最近更新 更多