Как сделать так, чтобы ярлыки запускались в пользовательском 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;
});
Меню открывается следующим образом (класс хостинга является производным от QGraphicsView
):
m_mainContextMenu.exec(mapToGlobal(m_clickedPos));
Меню показывает действие ОК, но оно не запускается Ctrl+C
, Я использовал тот же подход к действиям в моем главном меню, так почему это отличается?
Я также попытался установить некоторые другие ярлыки, но ничего не работает.
1 ответ
Вот один из способов сделать это:
- Помимо добавления действия в контекстное меню, добавьте действие в родительский виджет (тот, для которого действие должно быть локальным, скажем, в виде списка):
m_listview->addAction(m_copyNodeAction);
- Установите контекст ярлыка действия на
Qt::WidgetWithChildrenShortcut
:
m_copyNodeAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
- Убедитесь, что создаваемое вами контекстное меню использует ваш виджет как родительский:
auto* m_mainContextMenu = new QMenu{tr("Main Context Menu"), m_listview};
Следует учесть несколько вещей:
По умолчанию это не закрывает контекстное меню при запуске действия, но это довольно тривиально реализовать самостоятельно.
Это позволяет вам запускать действие без отображения контекстного меню (также довольно тривиально для обхода, хотя зачем вам это нужно?)
По некоторым предварительным тестам, похоже, что QtCreator также обрабатывает ярлыки таким образом, и кажется правильным подходом в стиле Qt к этому, хотя это всего лишь мой 2ct.
Следующий пример воспроизводит вашу ошибку. Я также отлаживал в Qt Framework и проходил через QMenu::keyPressEvent
а также QAction::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();
}