Swing的KeyListener和多个键同时按下

Posted

技术标签:

【中文标题】Swing的KeyListener和多个键同时按下【英文标题】:Swing's KeyListener and multiple keys pressed at the same time 【发布时间】:2011-02-07 02:46:22 【问题描述】:

当同时按下两个键盘键时,是否有任何常规方法可以跟踪事件? 我有几个想法,例如记住键和事件的生成时间,以便我们可以在连续的事件处理程序调用中检查这两个事件之间的时间差并确定它是否是双按钮事件。但它看起来像一个杂物。

【问题讨论】:

【参考方案1】:

使用一个集合来记住当前按下了哪些键,并检查每次按下一个键时是否按下了多个键。

class MultiKeyPressListener implements KeyListener 
    // Set of currently pressed keys
    private final Set<Integer> pressedKeys = new HashSet<>();

    @Override
    public synchronized void keyPressed(KeyEvent e) 
        pressed.add(e.getKeyCode());
        Point offset = new Point();
        if (!pressedKeys.isEmpty()) 
            for (Iterator<Integer> it = pressedKeys.iterator(); it.hasNext();) 
                switch (it.next()) 
                    case KeyEvent.VK_W:
                    case KeyEvent.VK_UP:
                        offset.y = -1;
                        break;
                    case KeyEvent.VK_A:
                    case KeyEvent.VK_LEFT:
                        offset.x = -1;
                        break;
                    case KeyEvent.VK_S:
                    case KeyEvent.VK_DOWN:
                        offset.y = 1;
                        break;
                    case KeyEvent.VK_D:
                    case KeyEvent.VK_RIGHT:
                        offset.x = 1;
                        break;
                
            
        
        System.out.println(offset); // Do something with the offset.
    

    @Override
    public synchronized void keyReleased(KeyEvent e) 
        pressedKeys.remove(e.getKeyCode());
    

    @Override
    public void keyTyped(KeyEvent e)  /* Not used */ 

【讨论】:

抱歉,我不明白如何使用它。请你再给我一个例子好吗?如何同时使用每个键? 由于 Java 1.7 HashSet 必须声明为:Set&lt;Character&gt; pressed = new HashSet&lt;&gt;(); @ErnestasGruodis 不是“必须”,您的意思是“可能”。可以选择不那么冗长。无论如何,我更新了它并添加了一个实际的使用示例。【参考方案2】:

KeyListener 接口允许分别检测按键的按下和释放。因此,您可以维护一组“活动键”,即已按下但尚未释放的键。

【讨论】:

@K_7:一个 Set 将强制项目的唯一性和更快的查找(例如,如果您使用 HashSet) 我也猜到了。感谢您的确认!【参考方案3】:

如果 7 年后我尝试这样做(只是为了看看是否可能),其他人也可能......

下面的代码控制8轴方向的运动,在cmets中有解释。但基本上,KeyListener 只是定义了可以移动的位置,然后Thread 将结合可能的目的地并移动JLabel

package tests;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class Move8Axis extends JFrame 

    private static final long serialVersionUID = 7722803326073073681L;

    private boolean left = false;
    private boolean up = false;
    private boolean down = false;
    private boolean right = false;

    private JLabel lbl = new JLabel("#");


    public Move8Axis() 
        // Just setting up the window and objects
        setSize(400, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        lbl.setBounds(100, 100, 20, 20);
        add(lbl);
        setLocationRelativeTo(null);

        // Key listener, will not move the JLabel, just set where to
        addKeyListener(new KeyListener() 
            @Override
            public void keyTyped(KeyEvent e) 
            @Override
            public void keyReleased(KeyEvent e) 
                if (e.getKeyCode() == KeyEvent.VK_LEFT) left = false;
                if (e.getKeyCode() == KeyEvent.VK_RIGHT) right = false;
                if (e.getKeyCode() == KeyEvent.VK_UP) up = false;
                if (e.getKeyCode() == KeyEvent.VK_DOWN) down = false;
            
            @Override
            public void keyPressed(KeyEvent e) 
                if (e.getKeyCode() == KeyEvent.VK_LEFT) left = true;
                if (e.getKeyCode() == KeyEvent.VK_RIGHT) right = true;
                if (e.getKeyCode() == KeyEvent.VK_UP) up = true;
                if (e.getKeyCode() == KeyEvent.VK_DOWN) down = true;
            
        );

        // This thread will read the 4 variables left/right/up/down at every 30 milliseconds
        // It will check the combination of keys (left and up, right and down, just left, just up...) 
        // And move the label 3 pixels
        new Thread(new Runnable() 
            @Override
            public void run() 
                try 

                    while (true)   
                        if (left && up) 
                            lbl.setBounds(lbl.getX() - 3, lbl.getY() - 3, 20, 20);
                         else if (left && down) 
                            lbl.setBounds(lbl.getX() - 3, lbl.getY() + 3, 20, 20);
                         else if (right && up) 
                            lbl.setBounds(lbl.getX() + 3, lbl.getY() - 3, 20, 20);
                         else if (right && down) 
                            lbl.setBounds(lbl.getX() + 3, lbl.getY() + 3, 20, 20);
                         else if (left) 
                            lbl.setBounds(lbl.getX() - 3, lbl.getY(), 20, 20);
                         else if (up) 
                            lbl.setBounds(lbl.getX(), lbl.getY() - 3, 20, 20);
                         else if (right) 
                            lbl.setBounds(lbl.getX() + 3, lbl.getY(), 20, 20);
                         else if (down) 
                            lbl.setBounds(lbl.getX(), lbl.getY() + 3, 20, 20);
                         

                        Thread.sleep(30);
                    

                 catch (Exception ex) 
                    ex.printStackTrace();
                    System.exit(0);
                
            
        ).start();
    

    public static void main(String[] args) 
        new Move8Axis();
    

【讨论】:

与 AWT / Swing 组件的交互只能从 Event Dispatch Thread 发生。因此,构造函数调用和标签更改不得发生在另一个线程中。对于更新标签,重复的timer 也非常适合。

以上是关于Swing的KeyListener和多个键同时按下的主要内容,如果未能解决你的问题,请参考以下文章

简单的 KeyListener 不起作用

KeyListener 如何检测组合键(例如,ALT + 1 + 1)

第十三周总结

十三周课程总结

KeyListener 随机停止工作。键绑定?

第十三周课程总结