Qt覆盖小部件快捷方式(窗口快捷方式)

时间:2017-07-04 22:50:31

标签: qt

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

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

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

我使用postEvent作为接收者在sendEvent内使用了eventFilterMainWindow,但忽略了这些事件:

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;
}

1 个答案:

答案 0 :(得分:3)

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

  

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

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

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

这是如何运作的:

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

2.将事件过滤器从p.1安装到小部件,如果覆盖,则应忽略快捷操作。

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

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!";
}

示例调试输出:

  

为QLineEdit忽略QFlags(ControlModifier)+ V(0x575b10,name =“lineEdit”)

     

来自窗口快捷方式的Hello!

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

更新:很快 - 您忽略了基础窗口小部件快捷方式事件并将其传播到父窗口小部件。

下面是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)
  5. 第二组 - 差异发生的地方......

    对于Ctrl-Z - lineEdit接收Ctrl + Z KeyPress事件,触发撤消操作:

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

      这里MainWindow没有收到任何事件,不依赖于它是否有Ctrl + Z动作快捷方式,它只是被QLineEdit吞噬

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

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

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

      5. 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)
        5. <强> P.S。我真的不知道为什么会发生这种情况 - 但这只是它的工作方式:)