c++ 用Qt检查某个键是否按下

vbkedwbf  于 2023-06-25  发布在  其他
关注(0)|答案(7)|浏览(307)

我正在玩一些图形,我已经实现了简单的相机移动与箭头键。我的第一个方法是重写keyPressEvent来做类似的事情:

switch(key)
{
   case up: MoveCameraForward(step); break;
   case left: MoveCameraLeft(step); break;
   ...
}

这不像我希望的那样工作。当我按住,例如,前进键,相机向前移动“步”单位,然后停止一段时间,然后继续移动。我猜这就是事件的生成方式,以避免在长时间按键的情况下出现多个事件。
所以,我需要在Paint()例程中轮询键盘。我不知道如何使用Qt。我想有一个map<Key, bool>,它将在keyPressEventkeyReleaseEvent中更新,并在Paint()中轮询Map。有更好的主意吗?谢谢你的任何见解。

bejyjqdl

bejyjqdl1#

这并不能解决检测哪个键被按下的一般问题,但如果你只寻找键盘修饰符(shift、ctrl、alt等),你可以通过静态QApplication::keyboardModifiers()QApplication::queryKeyboardModifiers()方法检索。

qv7cva1a

qv7cva1a2#

因此,我需要在Paint()例程中轮询键盘。我不知道如何使用Qt。我想到了一个Map,它将在keyPressEvent和keyReleaseEvent中更新,并在Paint()中轮询该Map。
您的第二种方法是我会做的,除了我会使用一个连续的,周期性的QTimer事件来轮询键盘按下的Map,并在必要时调用QWidget::Update()函数来使显示小部件无效。在Paint()中执行非绘画操作是非常不鼓励的,原因有很多,但我不知道如何解释。

kh212irz

kh212irz3#

没有Qt API来检查是否按下了键。您可能需要为不同的平台编写单独的代码,并添加一些#ifdef逻辑。
在Windows上,您可以使用GetKeyState()GetKeyboardState(),两者都在windows.h中声明。

jv2fixgn

jv2fixgn4#

在使用Qt时,这并不直接,但Gluon团队一直在解决这个问题(沿着其他一些问题)。GluonInput解决了这个问题,并作为Gluon的一部分提供:http://gluon.gamingfreedom.org/它也是一个很好的、类似于Qt的API,所以虽然它是一个额外的依赖项,但你应该可以使用它。

ukdjmx9f

ukdjmx9f5#

这是由关键点的自动重复引起的:
当我按住,例如,前进键,相机向前移动“步”单位,然后停止一段时间,然后继续移动。
在QT5中,您可以检测QKeyEvent对象的函数isAutoRepeat()按下的键。如果按住键,则isAutoRepeat()将返回true。例如:

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    if (event->isAutoRepeat())
    {
        return;
    }

    if (!event->isAutoRepeat())
    {
        qDebug() << "[MainWindow::keyPressEvent()] " << event->key() << "; " << event->isAutoRepeat();
    }
}

void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
    if (event->isAutoRepeat())
    {
        return;
    }
    qDebug() << "[MainWindow::keyReleaseEvent()] " << event->key() << "; " << event->isAutoRepeat();
}
8ulbf1ek

8ulbf1ek6#

在Qt5中使用QGuiApplication::keyboardModifiers()和QGuiApplication::queryKeyboardModifiers()作为键盘修饰符

nwnhqdif

nwnhqdif7#

@ksming的答案很好,但不完整,并且可能存在未处理的边缘情况。在Windows和OSX上,当窗口被拖动、调整大小或失去焦点时,可能无法接收到按键事件。这可能意味着您的Map可能会进入不一致的状态。
处理此问题的最佳方法是在检测到这些事件之一时使用QEvent::NonClientAreaMouseButtonPress重置Map
那就是
1.当按下某个键时,请在Map中记下这一点
1.释放密钥后,将其从Map中移除
1.当窗口被拖动时,清除你的Map-这允许你保持在一个一致的状态,因为你不可能知道在这段时间内的状态。
缺点是当窗口被拖动或调整大小时,你不能处理事件,但我认为在大多数用例中这应该是好的。只要让用户在处理完窗口后再处理这些。另一种方法是以依赖于平台的方式处理密钥。
一个警告字-在OSX上,它似乎你必须从应用程序级别本身收听NonClientAreaMouseButtonPress。也就是说,小部件不会像在Windows上那样接收此事件。

class KeyPressFilter : public QObject {
public:
    bool eventFilter(QObject* aObject, QEvent* aEvent) final {
        if (aEvent->type() == QEvent::NonClientAreaMouseButtonPress) {
            // Handle your event here ...
            // Optionally return
        }
        return QObject::eventFilter(aObject, aEvent);
    }
};

{
    QApplication myApplication{...};
    
    KeyPressFilter myKeyFilter;
    myApplication.installEventFilter(&myKeyFilter);

    myApplication.exec();
}

像这样的东西应该能用
出于完全相同的原因,您可能也希望处理QEvent::WindowDeactivate(如果焦点在处理关键点时发生了变化)。
有关此问题的讨论的链接可在here(准确至QT 6.5.1)找到。

相关问题