如何在自定义 QMenu 中触发快捷方式?

How to make shortcuts trigger in a custom QMenu?

我有一个上下文菜单 (QMenu) 并向其添加复制操作,如下所示:

m_copyNodeAction = new QAction(tr("Copy node"), &m_mainContextMenu);
m_copyNodeAction->setShortcut(QKeySequence("Ctrl+C"));
m_copyNodeAction->setShortcutVisibleInContextMenu(true);

m_mainContextMenu.addAction(m_copyNodeAction);

QObject::connect(m_copyNodeAction, &QAction::triggered, [this] () {
    std::cout << "Copy node triggered!" << std::endl;
});

菜单是这样打开的(宿主class来源于一个QGraphicsView):

m_mainContextMenu.exec(mapToGlobal(m_clickedPos));

菜单显示动作正常,但Ctrl+C没有触发。我在主菜单中对操作使用了相同的方法,为什么会有所不同?

我也试过设置一些其他的快捷方式,但是没有用。

以下示例重现了您的错误。我也在Qt Framework内部调试,单步执行QMenu::keyPressEventQAction::event,但似乎没有正确处理按下的键。

QAction::event中事件类型QEvent::Shortcut从未发生过。作为一种解决方法,我建议您从 QAction 派生并实现您自己的 event 函数。

#include <QApplication>
#include <QFrame>
#include <QMenu>
#include <QAction>
#include <QDebug>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    QApplication::setAttribute(Qt::ApplicationAttribute::AA_DontShowShortcutsInContextMenus,false);
    auto widget = new QFrame;

    widget->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
    int id=widget->grabShortcut(QKeySequence::Delete, Qt::ShortcutContext::WidgetShortcut);

    QObject::connect(widget, &QFrame::customContextMenuRequested, [widget,id](const QPoint& pos) {
        QMenu menu(widget);
        menu.setShortcutEnabled(id, true);
        auto action = new QAction("&Copy node", &menu);
        action->setShortcut(QKeySequence(QKeySequence::Delete));
        action->setShortcutVisibleInContextMenu(true);
        action->setShortcutContext(Qt::ShortcutContext::WidgetShortcut);

        QObject::connect(action, &QAction::triggered, []() {
            qDebug() << "Copy node triggered!";
        });

        menu.addAction(action);
        menu.exec(widget->mapToGlobal(pos));
        });

    widget->show();
    return a.exec();
}

这是解决此问题的一种方法:

  1. 除了将操作添加到上下文菜单之外,还将操作添加到父窗口小部件(操作应该是本地窗口小部件,比方说列表视图):
m_listview->addAction(m_copyNodeAction);
  1. 将操作的​​ shortcut context 设置为 Qt::WidgetWithChildrenShortcut:
m_copyNodeAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
  1. 确保您创建的上下文菜单使用您的小部件作为其父级:
auto* m_mainContextMenu = new QMenu{tr("Main Context Menu"), m_listview};

有几点需要考虑:

  1. 默认情况下,这不会在触发操作时关闭上下文菜单,但是您自己实现起来相当简单

  2. 这允许您在不显示上下文菜单的情况下触发操作(也很容易绕行,但您为什么要这样做?)

通过一些初步测试,这似乎也是 QtCreator 处理快捷方式的方式,并且似乎是处理此问题的正确 Qt 式方式,尽管那只是我的 2ct。