跳过Java KeyEvents [英] Skipping over Java KeyEvents

查看:134
本文介绍了跳过Java KeyEvents的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序,用户可以按一个键来执行操作。那个事件花了很少的时间。用户还可以按住该键并连续多次执行操作。问题是keyPress()事件排队的速度比处理事件的速度快。这意味着在用户释放密钥后,事件将继续处理,这些事件是从先前按住密钥的用户排队的。我还注意到,直到最后的keyPress事件被处理之后才会发生keyRelease事件,无论密钥何时被实际释放。我希望能够
1.检测密钥释放事件并忽略将来的keyPress事件,直到用户实际再次按下该密钥。
2.在第一个完成之前不执行后续的keyPress事件,然后检测何时未按下该键,然后停止。

I have a program where the user can press a key to perform an action. That one event takes a small amount of time. The user can also hold down that key and perform the action many times in a row. The issues is that the keyPress() events are queued up faster than the events can be processed. This means that after the user releases the key, events keep getting processed that were queued up from the user previously holding down the key. I also noticed that the keyRelease event doesn't occur until after the final keyPress event is processed regardless of when the key was actually released. I'd like to be able to either 1. Detect the key release event and ignore future keyPress events until the user actually presses the key again. 2. Not perform a subsequent keyPress event until the first is one finished and then detect when the key is not pressed, and just stop.

有没有人知道怎么做?

推荐答案

免责声明:我感觉不舒服,所以这段代码很可怕,好像..它也病了。

Disclaimer: I am not feeling well so this code is horrific, as though.. it too is sick.

我想要发生什么:访问DirectInput以获取键盘状态,而不是事件。这远远超出了这个问题的范围。所以我们将保持自己的操作状态。

What I want to happen: To access DirectInput to obtain a keyboard state, instead of events. That is far beyond the scope of this question though. So we will maintain our own action state.

您遇到的问题是您在UI线程中执行操作。您需要生成一个工作线程并忽略后续事件,直到您的操作完成。

The problem you are having is that you are executing your action within the UI thread. You need to spawn a worker thread and ignore subsequent events until your action is completed.

在我给出的示例中,当字母'a'时我开始一个新动作按下或按下。在第一个操作完成之前,它不会生成另一个操作。该操作更新表单上的标签,显示在完成之前剩余的周期。

In the example I've given I start a new action when the letter 'a' is pressed or held down. It will not spawn another action until the first action has completed. The action updates a label on the form, displaying how many 'cycles' are left before it has completed.

还有另一个标签显示到目前为止发生了多少次操作。

There is also another label that displays how many actions have occurred thus far.

产生一个新操作

重要的一部分是让所有UI键事件发生,而不是在UI线程中阻塞,导致它们排队。

The important part is to let all the UI key events to occur, not blocking in the UI thread causing them to queue up.

public void keyPressed(KeyEvent e) {
    char keyChar = e.getKeyChar();
    System.out.println("KeyChar: " + keyChar);
    // Press a to start an Action
    if (keyChar == 'a') {
        if (!mAction.isRunning()) {
            mTotalActions.setText("Ran " + (++mTotalActionsRan) + " actions.");
            System.out.println("Starting new Action");
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    mAction.run();
                }
            });
            thread.start();
        }
    }
}

更新UI线程

如果您的操作对用户界面执行任何类型的更新,则需要使用 SwingUtilities.invokeLater 方法。此方法将使代码排队以在UI线程中运行。您不能在UI线程以外的线程中修改用户界面。此外,仅使用SwingUtilities更新UI组件。任何不在Component上调用方法的计算,处理等都可以在SwingUtilities.invokeLater的范围之外完成。

If your action performs any kind of updates to the User Interface, it will need to use the SwingUtilities.invokeLater method. This method will queue your code to run in the UI thread. You cannot modify the user interface in a thread other than the UI thread. Also, only use SwingUtilities to update UI components. Any calculations, processing, etc that does not invoke methods on a Component, can be done outside the scope of SwingUtilities.invokeLater.

完整代码列表

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stackoverflow_4589538;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class Main extends JFrame {

    private JLabel mActionLabel;
    private JLabel mTotalActions;
    private int mTotalActionsRan;

    private class MyAction {

        private boolean mIsRunning = false;

        public void run() {
            // Make up a random wait cycle time
            final int cycles = new Random().nextInt(100);
            for (int i = 0; i < cycles; ++i) {
                final int currentCycle = i;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                }
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                            mActionLabel.setText("Cycle " + currentCycle + " of " + cycles);
                    }
                });
            }
            completed();
        }

        public synchronized void start() {
            mIsRunning = true;
        }

        public synchronized void completed() {
            mIsRunning = false;
        }

        public synchronized boolean isRunning() {
            return mIsRunning;
    }
}
    private MyAction mAction = new MyAction();

    public Main() {
        setLayout(null);
        setBounds(40, 40, 800, 600);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                char keyChar = e.getKeyChar();
                System.out.println("KeyChar: " + keyChar);
                // Press A to start an Action
                if (keyChar == 'a') {
                if (!mAction.isRunning()) {
                        mTotalActions.setText("Ran " + (++mTotalActionsRan) + " actions.");
                        System.out.println("Starting new Action");
                        Thread thread = new Thread(new Runnable() {

                            public void run() {
                                mAction.run();
                            }
                        });
                        // I had this within the run() method before
                        // but realized that it is possible for another UI event
                        // to occur and spawn another Action before, start() had
                        // occured within the thread
                        mAction.start();
                        thread.start();
                    }
                }
            }

        @Override
            public void keyReleased(KeyEvent e) {
            }
        });

        mActionLabel = new JLabel();
        mActionLabel.setBounds(10, 10, 150, 40);

        mTotalActions = new JLabel();
        mTotalActions.setBounds(10, 50, 150, 40);

        add(mActionLabel);
        add(mTotalActions);
    }    

    public static void main(String[] args) {
        new Main().setVisible(true);
    }
}

这篇关于跳过Java KeyEvents的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆