0

It is very straightforward to connect to QMenu::triggered or QMenu::hovered signals by calling QObject::connect and pass the appropriate QAction.

However, I do not know how to use QMenu::aboutToHide signal, as there is no action passed to that signal.

How to use QMenu::aboutToHide and QMenu::aboutToShow signals or those are just virtual functions that can be overridden?

scopchanov
  • 7,966
  • 10
  • 40
  • 68
Igor
  • 5,620
  • 11
  • 51
  • 103

1 Answers1

1

The signals in the world of Qt are not functions, never invoke them. The signals notify that something has happened with the QObject and send information if necessary.

In the case of triggered and hovered it is necessary to send the QAction because several QActions in a QMenu, then the developer thought that it is necessary to know with which QAction was interacting. On the other hand with aboutToShow and aboutToHide the signal does not send anything because it wants to notify is that if the QMenu was shown or hidden, respectively. Is there any need to know that QMenu was shown or hidden if he did it ? no, because the sender did it, I do not use other properties that we do not have at hand.

Example of use:

#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QMainWindow w;

    QMenu *foo_menu = w.menuBar()->addMenu("Foo Menu");
    for(const QString & name: {"action1", "action2", "action3"}){
        foo_menu->addAction(name);
    }
    QObject::connect(foo_menu, &QMenu::aboutToShow, [](){
        qDebug()<<"aboutToShow";
    });
    QObject::connect(foo_menu, &QMenu::aboutToHide, [](){
        qDebug()<<"aboutToHide";
    });
    QObject::connect(foo_menu, &QMenu::triggered, [](QAction *action){
        qDebug()<< "triggered: " <<action->text();
    });
    QObject::connect(foo_menu, &QMenu::hovered, [](QAction *action){
        qDebug()<< "hovered: " <<action->text();
    });
    w.show();

    return a.exec();
}

And what happens if you have several QMenu that connect to the same slot? How do I know QMenu was shown or hidden?

The solution is to use sender() which is a method that belongs to the QObject class that returns the object that emitted the signal, in this case the QMenu.

Example:

#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QDebug>

class MainWindow: public QMainWindow{
public:
    MainWindow(QWidget *parent=nullptr):
        QMainWindow(parent)
    {
        for(const QString & name_of_menubar: {"bar1", "bar2", "bar3"}){
            QMenu *menu = menuBar()->addMenu(name_of_menubar);
            connect(menu, &QMenu::aboutToShow, this, &MainWindow::on_aboutToShow);
            connect(menu, &QMenu::aboutToHide, this, &MainWindow::on_aboutToHide);
            for(const QString & name: {"action1", "action2", "action3"}){
                menu->addAction(name);
            }
        }
    }
private slots:
    void on_aboutToShow(){
        if(QMenu *menu = qobject_cast<QMenu *>(sender()))
            qDebug()<<"aboutToShow" << menu->title();
    }
    void on_aboutToHide(){
        if(QMenu *menu = qobject_cast<QMenu *>(sender()))
            qDebug()<<"aboutToHide" << menu->title();
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • @scopchanov Well, I've never called a signal directly, in what specific cases would you call: `aboutToShow();`?, I have always emitted the signals with Q_EMIT, what is the difference between `Q_EMIT aboutToShow();` and `aboutToShow();`?. – eyllanesc Sep 30 '18 at 17:07
  • @scopchanov In C++ is a function declared by the developer but implemented by the MOC, in the world of Qt is not a function is a signal that must be invoked through Q_EMIT and for me is completely correct. – eyllanesc Sep 30 '18 at 18:17
  • 1
    @scopchanov this can be added, no problem, I will improve my description later and I will add it. – eyllanesc Sep 30 '18 at 18:23