我正在玩一些图形,我已经实现了简单的相机移动与箭头键。我的第一个方法是重写keyPressEvent
来做类似的事情:
switch(key)
{
case up: MoveCameraForward(step); break;
case left: MoveCameraLeft(step); break;
...
}
这不像我希望的那样工作。当我按住,例如,前进键,相机向前移动“步”单位,然后停止一段时间,然后继续移动。我猜这就是事件的生成方式,以避免在长时间按键的情况下出现多个事件。
所以,我需要在Paint()
例程中轮询键盘。我不知道如何使用Qt。我想有一个map<Key, bool>
,它将在keyPressEvent
和keyReleaseEvent
中更新,并在Paint()
中轮询Map。有更好的主意吗?谢谢你的任何见解。
7条答案
按热度按时间bejyjqdl1#
这并不能解决检测哪个键被按下的一般问题,但如果你只寻找键盘修饰符(shift、ctrl、alt等),你可以通过静态
QApplication::keyboardModifiers()
和QApplication::queryKeyboardModifiers()
方法检索。qv7cva1a2#
因此,我需要在Paint()例程中轮询键盘。我不知道如何使用Qt。我想到了一个Map,它将在keyPressEvent和keyReleaseEvent中更新,并在Paint()中轮询该Map。
您的第二种方法是我会做的,除了我会使用一个连续的,周期性的QTimer事件来轮询键盘按下的Map,并在必要时调用QWidget::Update()函数来使显示小部件无效。在Paint()中执行非绘画操作是非常不鼓励的,原因有很多,但我不知道如何解释。
kh212irz3#
没有Qt API来检查是否按下了键。您可能需要为不同的平台编写单独的代码,并添加一些
#ifdef
逻辑。在Windows上,您可以使用
GetKeyState()
和GetKeyboardState()
,两者都在windows.h
中声明。jv2fixgn4#
在使用Qt时,这并不直接,但Gluon团队一直在解决这个问题(沿着其他一些问题)。GluonInput解决了这个问题,并作为Gluon的一部分提供:http://gluon.gamingfreedom.org/它也是一个很好的、类似于Qt的API,所以虽然它是一个额外的依赖项,但你应该可以使用它。
ukdjmx9f5#
这是由关键点的自动重复引起的:
当我按住,例如,前进键,相机向前移动“步”单位,然后停止一段时间,然后继续移动。
在QT5中,您可以检测
QKeyEvent
对象的函数isAutoRepeat()
按下的键。如果按住键,则isAutoRepeat()
将返回true
。例如:8ulbf1ek6#
在Qt5中使用QGuiApplication::keyboardModifiers()和QGuiApplication::queryKeyboardModifiers()作为键盘修饰符
nwnhqdif7#
@ksming的答案很好,但不完整,并且可能存在未处理的边缘情况。在Windows和OSX上,当窗口被拖动、调整大小或失去焦点时,可能无法接收到按键事件。这可能意味着您的Map可能会进入不一致的状态。
处理此问题的最佳方法是在检测到这些事件之一时使用
QEvent::NonClientAreaMouseButtonPress
重置Map那就是
1.当按下某个键时,请在Map中记下这一点
1.释放密钥后,将其从Map中移除
1.当窗口被拖动时,清除你的Map-这允许你保持在一个一致的状态,因为你不可能知道在这段时间内的状态。
缺点是当窗口被拖动或调整大小时,你不能处理事件,但我认为在大多数用例中这应该是好的。只要让用户在处理完窗口后再处理这些。另一种方法是以依赖于平台的方式处理密钥。
一个警告字-在OSX上,它似乎你必须从应用程序级别本身收听
NonClientAreaMouseButtonPress
。也就是说,小部件不会像在Windows上那样接收此事件。像这样的东西应该能用
出于完全相同的原因,您可能也希望处理
QEvent::WindowDeactivate
(如果焦点在处理关键点时发生了变化)。有关此问题的讨论的链接可在here(准确至QT 6.5.1)找到。