I'm working in a project where I need to open (show or popup) automatically the items in the QMenuBar.
Let's say I have the next menu bar:
File Edit Help
-op1 -op1 -op1
-op2 -op2 -op2
To set an action (show the menu associated with that action) I use:
menuBar->setActiveAction(mymenuactionpointer);
As I know, I can use one of the following to get a list of pointers to the elements of QMenuBar:
QMenuBar::actions();
or
QList<Object*> lst1 = QMenuBar::findChildren<QObject*>();
QList<Object*> lst2 = QMenuBar::findChildren<QAction*>();
When I use QMenuBar::findChildren<QAction*>()
or MenuBar::actions()
I got a list of the menus in menubar, I mean, I got "File, Edit, Help"
from my QMenuBar, the size of the QList in this case is 3.
When I use QMenuBar::findChildren<QObject*>()
I got a list of QObject of size 6, which is the correct number of items in the menu bar. However, I have tried cast to QAction*
QAction *a = (QAction *)lst1.at(0);
QAction *a = qobject_cast<QAction*>(lst1.at(0));
QAction *a = dynamic_cast<QAction*>(lst1.at(0));
In all this cases a
is not NULL, but when I try to get the action name QAction::title()
it always causes me segmentation fault.
I have been searching and I found here that after getting the menubar actions list, one can ask to QAction::menu()
(which returns a valid QMenu pointer if the item is a menu) to know if the item is a QMenu, if yes, one can repeat getting the actions list of that menu, and continue iterating. But this does not work for me, I expected that for
QList<Object*> lst2 = QMenuBar::findChildren<QAction*>();
each element "File, Edit Help" QAction::menu()
returns a valid menu pointer, so I could get the list of the actions of each menu, but this does not work at all for me.
The correct way to enumerate a QMenu
is to use the actions()
functions, but there is a catch - some of the actions are submenus, and they need to be iterated recursively. In fact, each QMenu
is associated with a QAction
, and they both hold pointers to each other - see QMenu::menuAction() and QAction::menu().
It is crucial to understand that each QMenu is also associated with a QAction. So knowing that, the proper implementation is the following:
void enumerateMenu(QMenu *menu)
{
foreach (QAction *action, menu->actions()) {
if (action->isSeparator()) {
qDebug("this action is a separator");
} else if (action->menu()) {
qDebug("action: %s", qUtf8Printable(action->text()));
qDebug(">>> this action is associated with a submenu, iterating it recursively...");
enumerateMenu(action->menu());
qDebug("<<< finished iterating the submenu");
} else {
qDebug("action: %s", qUtf8Printable(action->text()));
}
}
}