【问题标题】:Qt override widget shortcut (window shortcut)Qt override widget 快捷方式(窗口快捷方式)
【发布时间】:2017-07-04 22:50:30
【问题描述】:

我有一个 Qt 应用程序,在 Qt Designer 表单操作中定义了多个窗口快捷方式。在焦点位于处理相同组合的小部件上(覆盖我的窗口快捷方式)时按下它们之前,快捷方式效果很好。

我希望有相反的行为:窗口快捷方式覆盖焦点小部件快捷方式。

我尝试使用eventFilter 并且可以捕获所需的事件,但我无法以调用全局快捷方式的方式重新发送它们。我可以使用大开关并自己调用操作,但我当然想避免这种情况。

我在eventFilter 中使用了postEventsendEvent,使用MainWindow 作为接收器,但这些事件被忽略了:

bool MainWindow::eventFilter(QObject*, QEvent* event) {
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
        if (keyEvent->key() == Qt::Key_Z
            && keyEvent->modifiers() == Qt::ControlModifier) {
            //Calling the triggers directly works
            ui->actionUndo->trigger();
            return true;
        } else if (keyEvent->modifiers().testFlag(
                       Qt::KeypadModifier)) {
            QKeyEvent* ev2
                = new QKeyEvent(keyEvent->type(), keyEvent->key(), 0);
            qDebug() << keyEvent << ev2;
            //This sendEvent doesn't work
            QApplication::sendEvent(ui->widget, ev2);
            event->accept();
            return true;
        } else {
            return false;
        }
    }
    return false;
}

【问题讨论】:

  • 您只需要使用QShortcutQt::ApplicationShortcut 上下文。或者我不明白你的逻辑和你想要做什么。
  • 您是否尝试过发帖到qApp 而不是某个小部件?
  • @DmitrySazonov 我试过 Qt::ApplicationShortcut 结果是一样的
  • @king_nak 我也试过了,同样... :(
  • sendEvent 中的 0 不正确吗?据说它是一个Qt::KeyboardModifiers,这可能就是你的重新发送事件没有得到正确处理的原因吗?意思是,您检查收到的事件是否有一个,然后重新发送没有它的新事件。

标签: qt


【解决方案1】:

作为解决方案之一,您可以安装QEvent::ShortcutOverride 事件过滤器:

对于 QEvent::ShortcutOverride 接收者需要明确接受 触发覆盖的事件。在关键事件上调用 ignore() 会将其传播到父小部件。事件向上传播 父小部件链,直到小部件接受它或事件过滤器 消耗它。

当某些小部件尝试覆盖快捷方式事件时,将调用该事件,例如只是一个简单的例子:

我只有一个新的 Qt 应用程序,其中包含一个 lineEdit 和带有 Ctrl+V 快捷方式的窗口菜单(覆盖 lineEdit 中的粘贴快捷方式)。

这里是如何工作的:

1.创建将忽略(返回true)快捷方式覆盖的过滤方法(我在示例应用程序中使用了MainWindow::eventFilter,但是您可以使用您需要或想要的任何过滤对象)。遵循 Qt 文档并使用上述的 accept()/ignore() 可能会更好,但是在我的应用程序上它工作得很好,没有它们只返回 true/false。

2.将 p.1 中的事件过滤器安装到小部件中,如果覆盖该小部件,则该小部件应忽略快捷方式。

3.我在设计器中添加了带有 Ctrl+V 快捷键的菜单操作。在下面的代码中,您会看到 "Hello from window shortcut!" - 菜单操作结果,当您尝试粘贴 (Ctrl+V) 而不是实际的 lineEdit 粘贴操作时。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->lineEdit->installEventFilter(this);
}

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (event->type() == QEvent::ShortcutOverride) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        // Ignore only the Ctrl + V shortcut override, you can customize check for your needs
        if (keyEvent->modifiers().testFlag(Qt::ControlModifier) && keyEvent->key() == 'V') {
            qDebug() << "Ignoring" << keyEvent->modifiers() << "+" << (char)keyEvent->key() << "for" << watched;
            event->ignore();
            return true;
        }
    }

    return QMainWindow::eventFilter(watched, event);
}

void MainWindow::on_action1_triggered()
{
    qDebug() << "Hello from window shortcut!";
}

示例调试输出:

忽略 QFlags(ControlModifier) + V for QLineEdit(0x575b10, name = "lineEdit")

您好,来自窗口快捷方式!

注意:不幸的是,您应该为所有不想手动覆盖快捷方式的小部件安装此类过滤器。

更新:很快 - 您将忽略底层小部件快捷方式事件并将其传播到父小部件。

下面是 Ctrl-Z(在编辑中触发撤消)和 Ctrl-V(在编辑中忽略而不是粘贴,并触发菜单操作)的比较:

块 I - 开始的事件对于 Ctrl-Z 和忽略的 Ctrl-V 是相同的:

  1. QLineEdit 收到 QKeyEvent(ShortcutOverride, Key_Control, ControlModifier)
  2. QLineEdit 收到 QKeyEvent(KeyPress, Key_Control, ControlModifier)
  3. MainWindow 收到 QKeyEvent(KeyPress, Key_Control, ControlModifier)
  4. QLineEdit 收到 QKeyEvent(ShortcutOverride, Key_Z, ControlModifier)

Block II - 不同之处...

对于Ctrl-Z——lineEdit接收到Ctrl+Z KeyPress事件,触发Undo操作:

  1. QLineEdit 收到 QKeyEvent(KeyPress, Key_Z, ControlModifier)

    这里的 MainWindow 没有收到任何事件,这取决于它是否有 Ctrl+Z 操作快捷方式,它只是被 QLineEdit 吞没了

对于 Ctrl-V - MainWindow 接收从 QLineEdit 传播的 Ctrl+V ShortcutOverride 事件:

  1. filterEvent 中执行 QLineEdit 代码时忽略“Ctrl+V”
  2. MainWindow 收到 QKeyEvent(ShortcutOverride, Key_V, ControlModifier)
  3. “来自窗口快捷方式的您好!”来自菜单 Action 的代码已触发插槽执行。

    这里 QLineEdit 在过滤器告诉它忽略 ShortcutOverride 后没有收到任何事件,而是执行 MainWindow 快捷方式

Block III - 结束事件对于 Ctrl-Z 和忽略的 Ctrl-V 也是相同的 - 只是按键释放事件:

  1. QLineEdit 收到 QKeyEvent(KeyRelease, Key_Z, ControlModifier)
  2. MainWindow 收到 QKeyEvent(KeyRelease, Key_Z, ControlModifier)
  3. QLineEdit 收到 QKeyEvent(KeyRelease, Key_Control)
  4. MainWindow 收到 QKeyEvent(KeyRelease, Key_Control)

附注我真的不知道为什么会这样 - 但这就是它的工作原理:)

【讨论】:

  • 谢谢!它有效,但我不太明白......我是在接受窗口快捷方式,还是我正在禁用子项的覆盖(在这种情况下为 LineEdit)?你能发布当用户按下一个键时会发生什么以及窗口快捷方式覆盖时函数调用的差异吗?
  • 哦,老实说,我不明白为什么 Qt 事件完全按照我观察到的方式流动,但我已经更新了答案,试图展示和解释我所看到的差异。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 2018-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多