Signals and Slots with QMenu and QMessageBox
-
I've recently started off with Qt and I'm in the process of writing a Qt Widgets app.
I first wanted to make a menu bar with a hamburger menu so I wrote my own component for it which is basically just an instance of QMenu with a Hamburger Menu Icon.
For some reason I haven't been able to get signals and slots working with this setup. I wanted to make a QMessageBox appear when the QMenu item gets clicked on or when its triggered() signal is emitted.
Here's my code for the HamburgerMenu class
hamburgermenu.h#ifndef HAMBURGERMENU_H #define HAMBURGERMENU_H #include <QMenu> #include <QMainWindow> class HamburgerMenu : public QMenu { Q_OBJECT public: HamburgerMenu(); void setupMenu(QMenuBar *parent); }; Q_DECLARE_METATYPE(HamburgerMenu); #endif // HAMBURGERMENU_H
and hamburgermenu.cpp
#include "hamburgermenu.h" #include <QMenuBar> HamburgerMenu::HamburgerMenu() { //setting up QMenu object with QIcon resource this->setIcon(QIcon(":/icons/hamburger_menu_icon.svg")); return; } void HamburgerMenu::setupMenu(QMenuBar *parent){ // adding QMenu to parent QMenuBar parent->addMenu(this); return; }
and here's what I do in my QMainWindow constructor to set this stuff up.
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , hamburger_menu(new HamburgerMenu) , alert_box(new QMessageBox) { ui->setupUi(this); hamburger_menu->setupMenu(this->menuBar()); // setting up an example message box to tests signals/slots alert_box->setText("You just clicked the burger menu! :)"); // register HamburgerMenu as metatype? qRegisterMetaType<HamburgerMenu>(); // connecting the menu signal to the message box slot bool ret = connect(hamburger_menu,&HamburgerMenu::triggered,this,&MainWindow::hamburger_clicked); if (!ret) // connect returned false, must have failed qDebug("Connect failed on hamburger menu signal"); } MainWindow::~MainWindow() { delete ui; delete hamburger_menu; delete alert_box; } void MainWindow::hamburger_clicked(QAction *action) { alert_box->exec(); qDebug("The hamburger clicked slot was called!"); }
I would appreciate any help in figuring out what's wrong. Thank you in advance
-
@DenizCaglar
The signal/slot is (correctly) for aQAction
getting triggered. But you have not added any.QAction
s, those are the menu items a user clicks on. See e.g. https://doc.qt.io/qt-6/qmenu.html#actions and https://doc.qt.io/qt-6/qaction.html#qaction-in-widget-applications or there must be Qt menu examples around. -
@JonB Do I'm slightly confused on the difference between QAction, QMenu.
I thought that QMenu was the items that we placed on the QMenuBar. They also have the triggered() signal. Why can't I just connect a slot to that?
And if I were to add a QAction, would it create a submenu item under my QMenu or is it going to be analogous to using an anchor tag in html where it won't be visible but make the component clickable?
-
@DenizCaglar
You should use a QToolButton for that as i'm doing here:
-
@DenizCaglar said in Signals and Slots with QMenu and QMessageBox:
Also I can't really see your example of QToolButton. Did you mean to send a link or some code?
First you create a QMenu:
// menu options QMenu* menu=new QMenu(this); QAction *action; action=menu->addAction(tr("About...")); action->setData(ToolMenu_About); action->setCheckable(false); menu->addSeparator(); action=menu->addAction(tr("Preferences...")); action->setData(ToolMenu_Prefs); action->setCheckable(false); //QShortcut* shortcut= new QShortcut(QKeySequence(QKeySequence::Preferences),this); //connect(shortcut,SIGNAL(activated()),this,SLOT(applicationShortcut())); action->setMenuRole(QAction::PreferencesRole); menu->addSeparator(); ....
then connect all the actions:
connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(optionMenuAction(QAction*)));
it's old code i'm using old connect syntax, use the new one.
then add the menu to the tool button:
toolButton->setMenu(menu);
-
Well, Qt has both a QMenu and a QMenuItem. Only the QMenuItem is supposed to trigger actions. The QMenu itself only has QMenuItems and submenus. So, its action is already defined.
Usually, the QMenuItems have QActions associated with it. For the QMenu::triggered signal the documentation states:
This signal is emitted when an action in this menu is triggered.
To me this reads that you have several entries inside the QMenu and one of these entries triggers an action. This is also why this signal contains the QAction as a parameter. My understanding would mean that clicking on the QMenu itself does not emit a triggered signal, but only clicking on a QMenuItem does.