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

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

【问题讨论】:

    标签: java swing keylistener


    【解决方案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 也非常适合。
    猜你喜欢
    • 2012-12-29
    • 2021-07-08
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 2016-01-27
    • 2013-06-12
    相关资源
    最近更新 更多