java swing键绑定 - 释放键的缺失操作

时间:2011-12-15 18:30:41

标签: java swing key key-bindings

注册了“SPACE”和“已发布SPACE”的键绑定,当空格是唯一按下/释放的键时,按照广告的方式工作,我注意到按下空格,然后按ctrl(或任何其他修改键),然后释放空间最后释放ctrl将导致执行与“SPACE”相关联的操作,但不会执行与“释放的SPACE”相关联的操作。

一旦不再按空格(或同时按下修改键),导致动作执行的首选方法是什么?我只在Windows 7,64位上尝试过这个。

import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
import java.awt.Cursor;

class Bind extends JPanel {
  {
    getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed");
    getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released");
    getActionMap().put("pressed", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("pressed");
        setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
      }
    });
    getActionMap().put("released", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("released");
        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
      }
    });
  }
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override public void run() {
        JFrame f = new JFrame("Key Bindings");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        f.add(new Bind());
        f.setSize(640, 480);
        f.setVisible(true);
      }
    });
  }
}

UPDATE :这是在释放空间之前意外点击ctrl,alt或shift时避免粘滞空间的方法:

import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
import java.awt.Cursor;

class Bind extends JPanel {
  {
    getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed");
    getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("ctrl released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("shift released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("shift ctrl released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("alt released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("alt ctrl released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("alt shift released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("alt shift ctrl released SPACE"), "released");
    getActionMap().put("pressed", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("pressed");
        setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
      }
    });
    getActionMap().put("released", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("released");
        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
      }
    });
  }
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override public void run() {
        JFrame f = new JFrame("Key Bindings");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        f.add(new Bind());
        f.setSize(640, 480);
        f.setVisible(true);
      }
    });
  }
}

2 个答案:

答案 0 :(得分:7)

有意义的是,当仍然按住Control键时,不会触发released SPACE事件。我希望能解雇control released SPACE事件。

将以下内容添加到您的代码中:

getInputMap().put(KeyStroke.getKeyStroke("control released SPACE"), "released");

出于同样的原因,如果您先按住Control键,SPACE事件将不会触发。因此,您还需要为control SPACE添加绑定。

您需要对所有修改键执行此操作,这可能是也可能不是跟踪关键事件的简单解决方案。

答案 1 :(得分:4)

您的操作系统可能不会触发keyReleased个事件,而只会触发keyPressedkeyTyped个事件或其他组合,因此请先检查一下。您可能只需要检查keyTyped个事件而不是keyReleased,您就可以完成它了。

简答:

使用bitmask或数组来跟踪当前处于“已按下”状态的键,然后使用那些值来触发事件。也就是说,不要直接使用Swing事件来触发应用程序中的响应 - 您需要一个基本上存储键盘状态的额外层,并从该状态开始执行相关操作。

当您收到按下“Space”键之类的事件时,还有一些方法(see the end of this tutorial - "isAltDown", "isCtrlDown" etc.)可以检查是否按下了修改键。

答案很长:

当按下并释放按键时,事件会被触发,这是正确的。它必须以这种方式工作,以便您可以支持应该单独处理这些事件的应用程序,而不是一起处理。一个例子(虽然这不是唯一的例子)是PC上的视频游戏,你可能会同时按下多个字母/修饰键(例如,A向左移动,W去前进)并且游戏必须将这两个事件视为不同的输入,而不是复合输入,从而导致你的前进左右移动。

所以,你基本上想做的事情,如果你需要处理复合输入,就有一个简单的应用程序需要响应的动作数组,以及它们相关的键绑定(无论是单键还是多键都没有'真的很重要)。当按下某个键时,你基本上会打开该键的标志,表示它当前处于“按下”状态,并在释放时清除该标志。

然后,要触发您的事件,您只需检查所有按下的键(通过检查哪些键“标志”处于活动状态),如果按下特定事件的键组合,则触发该事件。

如果您触发事件的键少于32个,那么您实际上可以使用bitmask和32位int值而不是数组执行此操作。事实上,如果可以的话,这样做会简单得多。如果您需要最多64个密钥,请使用long执行相同的操作。如果您触发事件的键很少(例如8个或更少),则可以使用8位short类型。