qtpyqt

The difference between QMenu.menuAction and QAction in signal processing


In the following code, I connect the triggered signals of QMenu.menuAction and QAction to similar slot functions. However, only the triggered signal of QAction is triggered. I am curious why this is?

menu = self.menuBar().addMenu("action_1")
menu.menuAction().triggered.connect(lambda: print("action_1"))
action = self.menuBar().addAction("action_2")
action.triggered.connect(lambda: print("action_2"))

Solution

  • The main purpose of the action returned from a QMenu menuAction() is to add that action to another "action container".

    The common cases are:

    Leaving out the third case, which is a bit of an exception, the first two cases are "action containers" that show a list of actions.

    Conceptually speaking, QMenuBar is similar to a persistent QMenu (see the documentation about using "tear-off" menus), for which some actions actually contain a sub menu: the menuAction() is what is shown in the parent menu (or the menu bar).

    Now, it's easy to get confused by the identical names of the triggered signals available for QMenu and QAction. There is an important difference, though:

    Considering all the above, the result is that:

    When you click the action named "action_2", you are only triggering that action, not the action of its parent menu. That's why you don't get the triggered signal from the menuAction(): the action associated with that menu has not being triggered (nor it should!).

    The triggered signal of the menu action of a QMenu is normally never used, and for obvious reasons: when the user clicks an item in a parent menu that refers to a sub menu (or a menu title in a menu bar) they usually want to just open that menu.

    Finally, there are cases for which the triggered signal of a menu action is used, and they're mostly used for advanced purposes: for instance, by creating a QMenu subclass that implements special calls (eg: when double clicking on a menu action of a submenu); those are very rare cases, though, normally implemented for special cases, done with high awareness of the Qt toolkit behavior and extended experience with it. Also, in those cases the triggered signal has to be explicitly emitted, because Qt doesn't provide ways to automatically emit that, based on the assumption that there's no direct way to trigger the action related to a menu.