QT - QAction :: eventFilter: ambiguous overload

Search here and others hosted as qtcentre I saw that this problem arose, but it may not seem like it works. I have a MainWindow widget with a QSplitter that contains two Panel widgets (subclasses from QFrame ). Each panel has a menu bar with identical associated QActions / Shortcuts .

I tried all combinations of ShortcutContexts with setShortcutContext () .

Contexts

WindowShortcut and ApplicationShortcut give the expected "ambiguous label overload."

So far, WidgetShortcut and WidgetWithChildrenShortcut are not doing anything.

If I activate the menu manually, they certainly work fine. I also tried to focus on parent widgets with overloaded enterEvent () .

Any ideas?

thanks.

main.h

#include <QMainWindow> #include <QFrame> QT_BEGIN_NAMESPACE class QAction; class QMenu; class QHBoxLayout; class QSplitter; class QWidget; QT_END_NAMESPACE class Pane: public QFrame { Q_OBJECT public: Pane(QWidget* parent = 0); protected: void enterEvent(QEvent *event); void leaveEvent(QEvent *event); private: void createMenus(); QMenuBar * m_menuBar; private Q_SLOTS: void split(); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); private: void createActions(); void createMenus(); void setupUi(QMainWindow *MainWindow); QMenu *fileMenu; QAction *exitAct; QWidget *centralwidget; QHBoxLayout *horizontalLayout; QSplitter *splitter; QFrame *frame; QFrame *frame_2; }; 

main.cpp

 #include <iostream> #include <QApplication> #include <QMainWindow> #include <QSplitter> #include <QFrame> #include <QMenuBar> #include <QBoxLayout> #include "main.h" Pane::Pane(QWidget* parent) : QFrame(parent) { setFrameShape(QFrame::StyledPanel); setFrameShadow(QFrame::Raised); QVBoxLayout *layout = new QVBoxLayout; QFrame::setLayout(layout); m_menuBar = new QMenuBar; QWidget *m_widget = new QWidget; layout->addWidget(m_menuBar); layout->addWidget(m_widget); layout->setContentsMargins(2, 2, 2, 2); show(); createMenus(); } void Pane::enterEvent(QEvent *event) { std::cout << "enter" << std::endl; setFocus(); setStyleSheet("QFrame { border: 1px solid rgb(127, 127, 0); }"); if (focusWidget()) std::cout << "focuswidget = " << focusWidget()->objectName().toUtf8().constData() << std::endl; } void Pane::leaveEvent(QEvent *event) { std::cout << "leave" << std::endl; clearFocus(); setStyleSheet("QFrame { border: 1px solid rgb(64, 64, 64); }"); } void Pane::split() { std::cout << "split pane" << std::endl; } void Pane::createMenus() { QMenu *paneMenu = m_menuBar->addMenu(tr("&Pane")); QAction *paneSplitAct = new QAction(tr("Split"), this); paneSplitAct->setShortcut(Qt::Key_S); paneSplitAct->setShortcutContext(Qt::WidgetWithChildrenShortcut); paneSplitAct->setStatusTip(tr("Split Pane")); connect(paneSplitAct, SIGNAL(triggered()), this, SLOT(split())); paneMenu->addAction(paneSplitAct); } MainWindow::MainWindow() { setupUi(this); createActions(); createMenus(); } void MainWindow::createActions() { exitAct = new QAction(tr("E&xit"), this); exitAct->setShortcuts(QKeySequence::Quit); exitAct->setStatusTip(tr("Exit the application")); connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); } void MainWindow::createMenus() { fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(exitAct); } void MainWindow::setupUi(QMainWindow *MainWindow) { if (MainWindow->objectName().isEmpty()) MainWindow->setObjectName(QString::fromUtf8("MainWindow")); MainWindow->resize(800, 600); centralwidget = new QWidget(MainWindow); centralwidget->setObjectName(QString::fromUtf8("centralwidget")); horizontalLayout = new QHBoxLayout(centralwidget); horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); splitter = new QSplitter(centralwidget); splitter->setObjectName(QString::fromUtf8("splitter")); splitter->setOrientation(Qt::Horizontal); frame = new Pane(splitter); frame->setObjectName(QString::fromUtf8("frame")); splitter->addWidget(frame); frame_2 = new Pane(splitter); frame_2->setObjectName(QString::fromUtf8("frame_2")); splitter->addWidget(frame_2); horizontalLayout->addWidget(splitter); MainWindow->setCentralWidget(centralwidget); QMetaObject::connectSlotsByName(MainWindow); } int main(int argc, char *argv[]) { QApplication app(argc, argv); app.setOrganizationName("Trolltech"); app.setApplicationName("Application Example"); MainWindow mainWin; mainWin.show(); return app.exec(); } 

main.pro

 HEADERS = main.h SOURCES = main.cpp CONFIG += no_keywords 

UPDATE: Adding a call to addAction(paneSplitAct) at the end of Pane::createMenus() in combination with the Qt::WidgetShortcut context seems to give me what I want.

From what I understand in the documents, it is supposed to create a context menu in widgets. It seems I am not getting one (right click I suppose), but this is normal since I don't want this. eventEvent() and leaveEvent() are still required to properly set focus.

+6
source share
3 answers

I had similar problems: two different widgets had the same shortcut for the action (different action between the widgets). So far, only one of the widgets was visible in the application, everything worked. As soon as both were visible, I received the message "ambiguous label overload".

Solution: both action contexts should be set correctly on Qt :: WidgetWithChildrenShortcut, then it worked fine - only in accordance with the current focus.

If only one action has the correct context, then the one that has the default context triggered and displayed a message.

If both actions do not have a context set (by default), the initiated action was initiated and a message is displayed.

So, if you add Action with a shortcut anywhere, do not forget to think about the correct context and its setting, limit yourself!

+4
source

AFAIK for most scenarios like this parameter, the context context for WidgetShortcut is the right thing. The problem is that your duplicate actions are in the menu bars that cannot have focus (in the traditional sense of widgets), so it does nothing.

It may make sense to add common actions to the main window and make them application shortcuts. Then, in the main window, the slots with which actions are launched, work out who the Pane object has focus on and clicks on it.

+1
source

This solution worked for me to trigger a shortcut action when the menu bar was disabled or not in use.

Add a shortcut regularly:

 void StingrayEditor::add_shortcut(const QJsonObject& item_json) { QString item_path = item_json["path"].toString(); QString shortcut = item_json["shortcut"].toString(); if (!shortcut.isEmpty()) { QKeySequence key_sequence = QKeySequence::fromString(shortcut); QAction* shortcut_action = new QAction(item_path, this); if (!key_sequence.isEmpty()) { shortcut_action->setShortcut(key_sequence); shortcut_action->setShortcutContext(Qt::ApplicationShortcut); } connect(shortcut_action, &QAction::triggered, this, [item_path]() { // Action to be executed }); // Add the action to the main window. addAction(shortcut_action); } } 

It is important that you use shortcut_action->setShortcutContext(Qt::ApplicationShortcut);

Then you will need to filter / listen for events to catch QEvent::Shortcut :

 bool StingrayEditor::eventFilter(QObject* obj, QEvent* e) { switch (e->type()) { case QEvent::Shortcut: { QShortcutEvent* sev = static_cast<QShortcutEvent*>(e); if (sev->isAmbiguous()) { foreach(const auto& action, actions()) { if (action->shortcut() == sev->key()) { action->trigger(); // Trigger the action that matches the ambigous shortcut event. return true; } } } } // ... default: break; } return false; } 

Do not forget to register for such events:

qApp->installEventFilter(this);

0
source

Source: https://habr.com/ru/post/914298/


All Articles