qtqt5qmenuqactionqkeysequence

How to make shortcuts trigger in a custom QMenu?


I have a context menu (QMenu) and add a copy action to it like this:

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

The menu is opened like this (the hosting class is derived from a QGraphicsView):

m_mainContextMenu.exec(mapToGlobal(m_clickedPos));

The menu shows the action OK, but it doesn't trigger by Ctrl+C. I have used the same approach for actions in my main menu so why is this different?

I have also tried to set some other shortcuts, but nothing works.


Solution

  • Here's one way to go about this:

    1. In addition to adding the action to the contextmenu, add the action to the parent widget (the one that the action should be local to, let's say a listview):
    m_listview->addAction(m_copyNodeAction);
    
    1. Set the action's shortcut context to Qt::WidgetWithChildrenShortcut:
    m_copyNodeAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    
    1. Make sure the context menu you create uses your widget as its parent:
    auto* m_mainContextMenu = new QMenu{tr("Main Context Menu"), m_listview};
    

    There's a few things to consider:

    1. By default this doesn't close the context menu when the action is triggered, but that's rather trivial to implement yourself

    2. This allows you to trigger the action without the context menu being shown (also rather trivial to circumnavigate, though why would you want to?)

    By some prelimenary testing, this appears to be how QtCreator handles shortcuts as well, and seems like the proper Qt-esque way of approaching this, though that's just my 2ct.