跳过 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.
Does anyone know how to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
免责声明:我感觉不舒服,所以这段代码很可怕,好像……它也病了。
我想要发生的事情:访问 DirectInput 以获取键盘状态,而不是事件。但这远远超出了这个问题的范围。所以我们会维持自己的action状态。
您遇到的问题是您正在 UI 线程中执行操作。您需要生成一个工作线程并忽略后续事件,直到您的操作完成。
在我给出的示例中,当按下或按住字母“a”时,我开始一个新操作。在第一个操作完成之前,它不会生成另一个操作。该操作会更新表单上的标签,显示在完成之前还剩多少个“周期”。
还有另一个标签显示到目前为止已发生的操作数量。
生成新操作
重要的是让所有 UI 按键事件发生,而不是在 UI 线程中阻塞导致它们排队。
UI 线程更新
如果您的操作对用户界面执行任何类型的更新,则需要使用
SwingUtilities.invokeLater
方法。此方法会将您的代码排队以在 UI 线程中运行。您不能在 UI 线程以外的线程中修改用户界面。另外,仅使用 SwingUtilities 来更新 UI 组件。任何不调用组件上的方法的计算、处理等都可以在 SwingUtilities.invokeLater 的范围之外完成。完整代码列表
Disclaimer: I am not feeling well so this code is horrific, as though.. it too is sick.
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.
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.
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.
Spawning a new action
The important part is to let all the UI key events to occur, not blocking in the UI thread causing them to queue up.
Updates to the UI Thread
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.Full Code Listing
这取决于您所使用的操作系统。这是 Windows 上的行为(这对我来说很有意义)。在 Unix 或 Mac 上,我相信您会收到多个 keyPressed、keyReleased 事件。因此,您的解决方案不应基于 keyReleased 事件。
那么您应该使用键绑定,而不是 KeyListener。阅读 Swing 教程中有关如何使用键绑定的部分了解更多信息。
当调用该操作时,您可以将其禁用。我不确定这是否会阻止 KeyStroke 再次工作,或者您是否仍然需要检查操作的启用状态。然后,当操作代码执行完毕后,您可以重新启用该操作。
此外,这个长时间运行的代码不应在 EDT 上执行。请阅读 Swing 教程中关于并发的部分,以获取有关此问题和解决方案的更多信息。
This depends on the OS you are using. This is the behaviour on Windows (which makes sense to me). On Unix or Mac I believe you get multiple keyPressed, keyReleased events. So you solution should not be based on keyReleased events.
Then you should be using Key Binding, not a KeyListener. Read the section from the Swing tutorial on How to Use Key Bindings for more information.
When the Action is invoked you can then disable it. I'm not sure if this will prevent the KeyStroke from working again or whether you will still need to check the enabled state of the Action. Then when the Action code is finished executing you can re-enable the Action.
Also, this long running code should not execute on the EDT. Read the section from the Swing tutorial on Concurrency for more information about this and for solutions.
您必须选择选项 1。一旦开始较长的流程,请设置一个布尔值,以指示您正在处理该流程,并丢弃其他传入的相同请求。完成该过程后,将布尔值设置回原值并允许其他事件。
You will have to go with option 1. Once you start your longer process, set a boolean of some time to indicate you are working on it and throw out other incoming identical requests. Once you complete the process set the boolean back and allow additional events.