【问题标题】:QKeyEvent isAutoRepeat not working?QKeyEvent isAutoRepeat 不起作用?
【发布时间】:2016-06-29 14:11:31
【问题描述】:

所以,我有一个应用程序,如果按住特定按钮,它会播放音频设备,当释放按钮时,它会停止音频设备。我使用keyPressEventKeyReleaseEvent 来实现这个,类似于下面的代码:

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    if(event->isAutoRepeat())
    {
        event->ignore();
    }
    else
    {
        if(event->key() == Qt::Key_0)
        {
            qDebug()<<"key_0 pressed"<<endl;
        }
        else
        {
            QWidget::keyPressEvent(event);
        }
    }
}

void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
    if(event->isAutoRepeat())
    {
        event->ignore();
    }
    else
    {
        if(event->key() == Qt::Key_0)
        {
            qDebug()<<"key_0 released"<<endl;
        }
        else
        {
            QWidget::keyReleaseEvent(event);
        }
    }
}

但显然isAutoRepeat 功能不起作用,因为我可以看到key_0 pressedkey_0 released 连续打印出来,尽管事实上我在按下它之后没有释放0 键。是我的代码错了还是有其他问题?

谢谢。

编辑

我认为这是因为MainWindow 失去了键盘焦点。我如何才能真正找出哪个小部件具有焦点?当按下Qt::Key_0 时,我实际上正在使用一些小部件,但我认为我将所有可能的小部件设置为Qt::NoFocus,我想它不起作用。

我试图通过执行以下操作来了解哪个小部件具有焦点:

QWidget * wigdet = QApplication::activeWindow();
qDebug()<<wigdet->accessibleName()<<endl;

但它总是打印一个空字符串。如何让它打印具有键盘焦点的小部件的名称?

【问题讨论】:

  • 你的班级是MainWindow 还是ConsoleMainWindow?好像你的问题有错别字
  • 其次,你的代码对我有用,刚刚测试过。文档状态:Note that if the event is a multiple-key compressed event that is partly due to auto-repeat, this function could return either true or false indeterminately。你是这种情况吗?
  • @IAmInPLS 抱歉打错了,我改了。我的课是 MainWindow。
  • 您的操作系统和 Qt 版本是什么?
  • @IAmInPLS Ubuntu LTS 14.04 和 Qt 5.2.1。我不认为该事件是多键压缩事件。它所做的只是在按下时增加音频设备的音量并在释放时减小它。这是一个多键压缩事件吗?

标签: c++ qt c++11 qkeyevent


【解决方案1】:

所以当我也偶然发现这个问题时(grabKeyboard 并没有真正帮助),我开始在 qtbase 中进行挖掘。它通过 xcb 连接到 X11,默认情况下,在重复按键的情况下,X11 为每个重复按键发送一个释放事件,紧跟一个按键事件。因此,按住一个键会导致一系列 XCB_BUTTON_RELEASE/XCB_BUTTON_PRESS 事件被发送到客户端(使用 xev 或this page 末尾的源进行尝试)。

然后,qt (qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp) 试图从这些事件中找出它是否是自动重复的情况:当收到一个版本时,它使用前瞻功能来确定它是否紧随其后(时间戳足够接近),如果是这样,它假定自动重复。

这并不总是有效,至少不是在所有平台上都有效。对于我的情况(运行 ubuntu 16.04 的旧的和过时的慢速笔记本电脑(Intel® Celeron(R) CPU N2830 @ 2.16GHz × 2)),它有助于在检查之前进入睡眠状态(500),允许发布后的新闻发布会事件到达...它在 qxcbkeyboard.cpp 的第 1525 行附近:

    // look ahead for auto-repeat
    KeyChecker checker(source->xcb_window(), code, time, state);
    usleep(500); // Added, 100 is to small, 200 is ok (for me)
    xcb_generic_event_t *event = connection()->checkEvent(checker);
    if (event) {
    ...

将此归档为QTBUG-57335

Nb:X 的行为可以通过使用

来改变
Display *dpy=...;
Bool result;
XkbSetDetectableAutoRepeat (dpy, true, &result);

然后它不会在按住键的情况下发送此释放-按下序列,但使用它需要对自动重复检测逻辑进行更多更改。

【讨论】:

    【解决方案2】:

    总之解决了。

    问题是我有一个小部件,它是 QGLWidget 的子类,我用它来显示来自 Kinect 的一些增强现实图像。每当按下键盘按钮时,此小部件都会接管键盘焦点。

    为了解决这个问题,我需要从MainWindow类中调用grabKeyboard函数(MainWindowQMainWindow的子类),所以this-&gt;grabKeyboard()是我需要在key_0时添加的行按下按钮,MainWindow 不会失去键盘焦点,然后在释放键时我需要添加行 this-&gt;releaseKeyboard() 以恢复正常行为,即其他小部件可以拥有键盘焦点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多