使用 Qt 检查某个键是否按下
我正在玩一些图形,并且我已经使用箭头键实现了简单的相机移动。我的第一个方法是重写 keyPressEvent 来执行如下操作:
switch(key)
{
case up: MoveCameraForward(step); break;
case left: MoveCameraLeft(step); break;
...
}
这并不像我希望的那样工作。例如,当我按住前进键时,相机会向前移动“步”单位,然后暂停一会儿,然后继续移动。我猜测这就是事件的生成方式,以避免在按键时间较长的情况下发生多个事件。
因此,我需要在 Paint()
例程中轮询键盘。我还没有找到如何用 Qt 做到这一点。我想到有一个 map
,它将在 keyPressEvent
和 keyReleaseEvent
中更新,并在 Paint( )
。还有更好的想法吗?感谢您的任何见解。
I am playing around with some graphics, and I have implemented simple camera movement with the arrow keys. My first approach was to override keyPressEvent
to do something like this:
switch(key)
{
case up: MoveCameraForward(step); break;
case left: MoveCameraLeft(step); break;
...
}
This doesn't work as I wish it would. When I press and hold, for example, the forward key, the camera moves forward "step" units, then halts for a while and then continues moving. I am guessing that this is how the event is generated, in order to avoid multiple events in case of a little bit long keypress.
So, I need to poll the keyboard in my Paint()
routine. I haven't found how to do it with Qt. I thought of having a map<Key, bool>
which would be updated in keyPressEvent
and keyReleaseEvent
and poll that map in Paint()
. Any better ideas? Thanks for any insights.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
没有 Qt API 用于检查按键是否被按下。
您可能必须为不同的平台编写单独的代码并添加一些
#ifdef
逻辑。在 Windows 上,您可以使用
GetKeyState()
和GetKeyboardState()
,它们都在windows.h
中声明。There is no Qt API for checking whether a key is pressed or not.
You may have to write separate code for different platforms and add a bit of
#ifdef
logic.On Windows you can use
GetKeyState()
andGetKeyboardState()
, both declared inwindows.h
.使用 Qt 时这并不简单,但 Gluon 团队一直在解决这个问题(以及其他许多问题)。 GluonInput 解决了这个问题,并作为 Gluon 的一部分提供:http://gluon.gamingfreedom.org/ 它也是一个很好的、类似 Qt 的 API,因此虽然它是一个额外的依赖项,但您应该可以使用它。
This is not straight forward when using Qt, but the Gluon team has been working on exactly that problem (along with a bunch of others). GluonInput solves the issue, and is available as part of Gluon: http://gluon.gamingfreedom.org/ It is also a nice, Qt-like API, so while it's an extra dependency, it should be possible for you to use it.
这是由自动重复按键引起的:
在 QT5 中,您可以通过
QKeyEvent
对象的函数isAutoRepeat()
检测按下的按键。如果按住该键,则isAutoRepeat()
将返回true
。例如:
This is caused by auto repeation of keys:
In QT5 you can detect key held down by function
isAutoRepeat()
ofQKeyEvent
object. If the key is held down thenisAutoRepeat()
will returntrue
.for example:
@ksming 的答案很好,但不完整,并且可能存在未处理的边缘情况。在 Windows 和 OSX 上,当窗口被拖动、调整大小或失去焦点时,可能不会接收到按键事件。这可能意味着您的地图可能会进入不一致的状态。
处理此问题的最佳方法是,每当检测到这些事件之一时,使用 QEvent::NonClientAreaMouseButtonPress 重置地图。
也就是说,
缺点是您无法在拖动窗口或调整窗口大小时处理事件,但我认为在大多数用例中这应该没问题。只需让用户在完成窗口处理后处理这些即可。另一种方法是以平台相关的方式处理密钥。
警告 - 在 OSX 上,您似乎必须从应用程序级别本身监听
NonClientAreaMouseButtonPress
。也就是说,小部件不会像 Windows 上那样接收此事件。像这样的东西应该可以工作
您可能还想出于完全相同的原因处理
QEvent::WindowDeactivate
(如果在处理按键时焦点发生变化)。可以找到有关此问题的讨论的链接 此处(从 QT 6.5.1 开始准确)
@ksming's answer is good, but not complete and has a possible edge case that is not handled. It is possible on Windows and OSX that key events will not be received as a window is dragged, resized or loses focus. This can mean your map can get into an inconsistent state.
The best way to handle this is to reset the map whenever one of these events is detected, using
QEvent::NonClientAreaMouseButtonPress
That is,
The downside is you cannot handle events as the window is dragged or resized, but I think in the majority of use cases this should be fine. Just let the user handle these when they are done with their handling of the window. The alternative is handling keys in a platform dependant manner.
A word of warning - on OSX it appears you must listen to
NonClientAreaMouseButtonPress
from the application level itself. That is, a widget will not receive this event like it will on Windows.Something like this should work
You might also want to handle
QEvent::WindowDeactivate
for exactly the same reason (if the focus is changed as keys are being handled).A link to a discussion on this issue can be found here (accurate as of QT 6.5.1)
在 Qt5 中使用 QGuiApplication::keyboardModifiers() 和 QGuiApplication::queryKeyboardModifiers() 作为键盘修改器
Use QGuiApplication::keyboardModifiers() and QGuiApplication::queryKeyboardModifiers() for keyboard modifiers in Qt5
这并不能解决检测按下哪些键的一般问题,但如果您只想查找键盘修饰符(shift、ctrl、alt 等),则可以通过静态
QGuiApplication::keyboardModifiers()
和QGuiApplication::queryKeyboardModifiers()
方法。This doesn't solve the general problem of detecting which keys are pressed, but if you are only looking for keyboard modifiers (shift, ctrl, alt, etc.), you can retrieve that through the static
QGuiApplication::keyboardModifiers()
andQGuiApplication::queryKeyboardModifiers()
methods.你的第二种方法是我会做的,除了我会使用连续的、周期性的 QTimer 事件来轮询键盘按下的地图,并在必要时调用 QWidget::Update() 函数来使显示小部件无效。由于多种原因,强烈建议不要在 Paint() 内执行非绘画操作,但我不知道如何解释这一点。
Your second method is what I would have done, except that I would use a continuous, periodic QTimer event to poll the keyboard-pressed map and call QWidget::Update() function when necessary to invalidate the display widget instead. Performing non-painting operations inside Paint() is strongly discouraged for many reasons but I do not know how to explain that well.