Archived:Qt Menus
Qt C++ UIs are deprecated - QML should be used instead where possible.
his article provides a comprehensive explanation of how to create QMainWindow application menus in Qt on the Symbian platform. It includes information about how to change menu softkey text, how to use menu icons, and how to support menus in view switching applications.
Article Metadata
It highlights the minor platform specific issues, and is intended to be complementary to the generic Qt Menus Example and reference documentation: QMainWindow, QMenu, QMenuBar, QAction, QActionGroup
Overview
Qt is a true cross platform application framework; Application menus are defined using platform-neutral classes that, when compiled, result in menus with the same look and feel as those written using native libraries.
On Symbian, Qt implements the menu using native menu libraries. While the menu specification is generic, this means that there are several considerations for Qt developers targeting Symbian platform devices:
- Some menu functionality that works on desktop is not supported on the Symbian platform
- Icons cannot be displayed in menus or menu items - QTBUG-7951
- Separators between menus/menu items aren't displayed
- Menu actions that are disabled are made invisible rather than "greyed out"
- Menu text cannot be styled (for example made bold or italic)
- Context menus aren't supported (or needed)
- Keyboard shortcuts and shortcut text aren't supported (or needed)
- Nesting of menus and menu items is discouraged
- While Symbian applications can deeply nest menus, this can make them harder to use. It is more typical to have menu actions at the top level, or at most one level down.
- Qt supports menus only in the QMainWindow itself; applications that have several "views" on the application data must implement mechanisms to update the main window menu when the view changes.
Example code
The Nokia Menus Example demonstrates most aspects of using menus. Screenshots of the example running on Symbian and Windows (Vista) are shown below. The Symbian menu is selected by clicking the "Options" softkey. The second and third screenshots show the nested menus. Note the styling that is missing from the "Bold" and "Italic" menu items, along with the separators and keyboard accelerators.
While the example is useful it does omit a number of menu related topics:
- Having actions/menu items as the top level menu
- Changing the "Options" softkey text used to launch the menu
- Changing the "Options" softkey text to an icon
- Having icons as menu items
- Code to remove spurious "Actions" menu from the top level menu options
These, along with the general use of menus are explained in the following sections.
The "Options" softkey must be visible in order to select the menu. In order to ensure that the softkeys are not covered by the main window the menu example calls QMainWindow::showMaximized() to size the window to fit between the softkeys at the bottom of the screen and the status up the top:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
#if defined(Q_OS_SYMBIAN)
window.showMaximized();
#else
window.show();
#endif
return app.exec();
}
Its also possible to just expose the softkeys (hide the status pane) by setting the window to be full screen and providing a windows hint. This is discussed in Qt Softkeys.
Most Symbian applications use top level menu actions (QAction) which are added directly to the main windows menu bar (QMainWindow::menuBar()), as shown on the image to the right.
Menu actions are created using QAction; these are connected to the appropriate slot, and then added to a QMenuBar
//Create actions with the main window as parent
QAction* myAction1=new QAction(tr("Option 1"), this);
QAction* myAction2=new QAction(tr("Option 2"), this);
//Connect the actions to slots in your main window
connect(myAction1, SIGNAL(triggered()), this, SLOT(mySlotFunction1()));
connect(myAction2, SIGNAL(triggered()), this, SLOT(mySlotFunction2()));
//Add the actions to the menubar (or a menu)
menuBar()->addAction(myAction1);
menuBar()->addAction(myAction2);
Note that the QAction is created using the tr function in order to ensure that the menu text is visible to Qt's translation system. If the code is not to run on desktops there is no need to declare shortcuts in the text or add any styling.
The menuBar takes ownership of the action; if you don't need to keep a handle to the action for later use, you can create the action and its signal/slot connections and add it to the menubar in one go:
menuBar()->addAction("Option 1", this, SLOT(mySlotFunction()));
We can also add menus/nested menus to the tree. The menu example shows this:
//Call addMenu on the menuBar to get a QMenu*
editMenu = menuBar()->addMenu(tr("&Edit"));
//Add actions to the menu
editMenu->addAction(undoAct);
editMenu->addAction(redoAct);
...
helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
Note that the menuy softkey "Options" appears as soon as you create the first menu item.
The menu example does not have any focussable widgets. When you create a real application it probably will, and if you select one of these and then open the menu, you'll see a menu item labeled "Actions". This is a placeholder for the widget context menu, which isn't needed on Symbian applications.
You can individually call setContextMenuPolicy(Qt::NoContextMenu) on every widget to remove this item; however it is usually easier to call it on all widgets in the application in your main() function:
/* Remove context menu from the all widgets. */
QWidgetList widgets = QApplication::allWidgets();
QWidget* w=0;
foreach(w,widgets) {
w->setContextMenuPolicy(Qt::NoContextMenu);
}
A QAction can be disabled or made invisible using the methods QAction::setDisabled() and QAction::setDisabled(). On desktop platforms the distinction is that the action remains visible but greyed out if it is disabled - on the Symbian platform either approach will make the item invisible.
Menu items can be "checked" - on the Symbian platform they are displayed with a "tick" mark next to them. To make a menu action checkable you need to call setCheckable(true) on it. You can then set it as checked using setChecked(true):
Sometimes you need to create a group of menu actions where only one is selectable - equivalent to a single selection radio button. This can be done using the QActionGroup, as demonstrated in the menu example:
alignmentGroup = new QActionGroup(this);
alignmentGroup->addAction(leftAlignAct);
alignmentGroup->addAction(rightAlignAct);
alignmentGroup->addAction(justifyAct);
alignmentGroup->addAction(centerAct);
leftAlignAct->setChecked(true);
The default menu softkey will use the equivalent of "Options" appropriate for the current phone language. You can change this text by adding your own menu, as shown below:
QMenu* menu = new QMenu(this);
menu->addAction("Option 1", this, SLOT(menuItemTriggered()));
menu->addAction("Option 2", this, SLOT(menuItemTriggered()));
menu->addAction("Option 3", this, SLOT(menuItemTriggered()));
QAction* myMenuKey = new QAction("MyMenu", this);
myMenuKey->setSoftKeyRole(QAction::PositiveSoftKey);
myMenuKey->setMenu(menu);
addAction(myMenuKey );
Note however that the default menu text is localized on your behalf; if you change it then you may need to provide your own translations (a better alternative if the default text is unacceptable may be to use an image for the softkey).
Not supported at present. See https://bugreports.qt-project.org/browse/QTBUG-7951
You can't simply add an icon to the default menu softkey because its QAction is internal. Instead you first need to create a new menu/menu softkey, as discussed in #How do I change the menu softkey text and then you add a softkey icon, as discussed in Qt Softkeys#How to use softkey icons.
QMenu* menu = new QMenu(this);
menu->addAction("Option 1", this, SLOT(menuItemTriggered()));
menu->addAction("Option 2", this, SLOT(menuItemTriggered()));
menu->addAction("Option 3", this, SLOT(menuItemTriggered()));
QAction* myMenuKey = new QAction("MyMenu", this);
myMenuKey->setSoftKeyRole(QAction::PositiveSoftKey);
myMenuKey->setIcon(QPixmap(":/icons/icons/menu_icon.png")); //add icon for the menu softkey!
myMenuKey->setMenu(menu);
addAction(myMenuKey );
Symbian applications often have many different "views", each with their own context sensitive options menu. For example, a contact application would have a top level view to display contacts and a menu that defines selection operations. Once you're editing a contact the options available on the menu will be quite different.
In a Qt application this sort of behaviour requires some additional implementation, because while any widget can have a menubar or menu, only the menu belonging to the QMainWindow itself is displayed. There are a number of ways this can be handled. One way is to have a view switching architecture where the view sends a signal with its actions to the main window.
An alternative is to have an architecture where each "view" widget has its own menu. When a view is displayed the main window clears the menu and repopulates itself with items from the current widget's menu. This approach is used in the Nokia Developer QStackableWidget example.
[--hamishwillee : Provide link to example and some code fragments?]
Qt Creator
Qt Creator allows you to create menus and menu actions "visually" using Qt Designer, by nesting actions and menus within menus. This may not be suitable for Symbian applications because there is no way to specify that a top level menu item is an action rather than a menu.
You can define a context menu that appears below a button when it is activated (for example, when it is pressed). This differs from a context menu, which is usually activated by a right mouse click.
The code fragment shows how to add the menu to a push button that has been defined using the Qt Creator UI Designer, and then launch it when the button is clicked:
QMenu* menu = new QMenu(this);
menu->addAction("Option 1", this, SLOT(menuItemTriggered()));
menu->addAction("Option 2", this, SLOT(menuItemTriggered()));
menu->addAction("Option 3", this, SLOT(menuItemTriggered()));
ui->pushButton->setMenu (menu );
connect(ui->pushButton,SIGNAL(clicked()),ui->pushButton,SLOT(showMenu()));
Summary
Qt menus on the Symbian platform are defined in the same way as on any other platform. However the menu itself is rendered quite differently than on desktop and some features do not behave as well (or at all) in a mobile context. This article has shown how menus work in standard Qt on Symbian applications, and what menu behaviour does not work.
Note that this content was originally hosted on the Symbian Foundation developer wiki.


(no comments yet)