|  | Home · Examples

# Menus Example

Code:

- Menus.java

The Menus example demonstrates how menus can be used in a main window application.

A menu widget can be either a pull-down menu in a menu bar or a standalone context menu. Pull-down menus are shown by the menu bar when the user clicks on the respective item or presses the specified shortcut key. Context menus are usually invoked by some special keyboard key or by right-clicking.

A menu consists of a list of action items. In applications, many common commands can be invoked via menus, toolbar buttons as well as keyboard shortcuts. Since the user expects the commands to be performed in the same way, regardless of the user interface used, it is useful to represent each command as an action.

The Menus example consists of one single class, `Menus`, extending the QMainWindow class. QMainWindow provides a main application window, with a menu bar, tool bars, dock widgets and a status bar around a large central widget. When choosing one of the action items in our application, it will display the item's path in its central widget.

## Menus Class Implementation

First, we declare the various menus and actions as well as a simple information label in the application wide scope:

    public class Menus extends QMainWindow {

        QMenu fileMenu;
        QMenu editMenu;
        QMenu formatMenu;
        QMenu helpMenu;
        QActionGroup alignmentGroup;
        QAction newAct;
        QAction openAct;
        QAction saveAct;
        QAction printAct;
        QAction exitAct;
        QAction undoAct;
        QAction redoAct;
        QAction cutAct;
        QAction copyAct;
        QAction pasteAct;
        QAction boldAct;
        QAction italicAct;
        QAction leftAlignAct;
        QAction rightAlignAct;
        QAction justifyAct;
        QAction centerAct;
        QAction setLineSpacingAct;
        QAction setParagraphSpacingAct;
        QAction aboutAct;
        QAction aboutQtAct;
        QAction aboutQtJambiAct;
        QLabel infoLabel;

The QMenu class provides a menu widget for use in menu bars, context menus, and other popup menus while the QAction class provides an abstract user interface action that can be inserted into widgets.

In some situations it is useful to group actions together, e.g., we have a Left Align action, a Right Align action, a Justify action, and a Center action, and we want only one of these actions to be active at any one time. One simple way of achieving this is to group the actions together in an action group using the QActionGroup class.

        public Menus() {
            QWidget widget = new QWidget();
            setCentralWidget(widget);

In the constructor, we start off by creating a regular QWidget and make it our main window's central widget. Note that the main window takes ownership of the widget pointer and deletes it at the appropriate time.

            QWidget topFiller = new QWidget();
            topFiller.setSizePolicy(QSizePolicy.Policy.Expanding,
                                    QSizePolicy.Policy.Expanding);

            infoLabel = new QLabel(tr("<i>Choose a menu option, "
                                      + "or right-click to invoke "
                                      + "a context menu</i>"));
            infoLabel.setFrameStyle(QFrame.Shape.StyledPanel.value()
                                    | QFrame.Shadow.Sunken.value());
            infoLabel.setAlignment(AlignmentFlag.AlignCenter);

            QWidget bottomFiller = new QWidget();
            bottomFiller.setSizePolicy(QSizePolicy.Policy.Expanding,
                                       QSizePolicy.Policy.Expanding);

            QVBoxLayout layout = new QVBoxLayout();
            layout.setMargin(5);
            layout.addWidget(topFiller);
            layout.addWidget(infoLabel);
            layout.addWidget(bottomFiller);
            widget.setLayout(layout);

Then we create the information label as well as a top and bottom filler that we add to a layout which we install on the central widget. QMainWindow objects come with their own customized layout and setting a layout on a the actual main window, or creating a layout with a main window as a parent, is considered an error. You should always set your own layout on the central widget instead.

            createActions();
            createMenus();

            statusBar().showMessage(tr("A context menu is available by "
                                       + "right-clicking"));

            setWindowTitle(tr("Menus"));
            setMinimumSize(160, 160);
            resize(480, 320);
            setWindowIcon(new QIcon("classpath:com/trolltech/images/qt-logo.png"));
        }

To simplify the constructor, we have chosen to create the actions and menus using two convenience methods: `createActions()` and `createMenus()`. We will get back to these shortly.

QMainWindow's statusBar() method returns the status bar for the main window (if the status bar does not exist, this method will create and return an empty status bar). We initialize the status bar and window title, resize the window to an appropriate size as well as ensure that the main window cannot be resized to a smaller size than the given one. Finally, we set the window icon.

Now, let's take a closer look at the `createActions()` convenience method that creates the various actions:

        void createActions() {
            newAct = new QAction(tr("&New"), this);
            newAct.setShortcut(tr("Ctrl+N"));
            newAct.setStatusTip(tr("Create a new file"));
            newAct.triggered.connect(this, "newFile()");
    ...

A QAction object may contain an icon, a text, a shortcut, a status tip, a "What's This?" text, and a tooltip. Most of these can be set in the constructor, but they can also be set independently using the provided convenience methods.

In the `createActions()` method, we first create a `newAct` action. We make Ctrl+N its shortcut using the QAction.setShortcut() method, and we set its status tip using the QAction.setStatusTip() method (the status tip is displayed on all status bars provided by the action's top-level parent widget). We also connect its triggered() signal to the `newFile()` method.

The rest of the actions are created in a similar manner. Please see the source code for details.

Note that the methods corresponding to the various actions are left out of this documentation since they are trivial, i.e., most of them are only displaying the action's path in the main window's central widget.

            alignmentGroup = new QActionGroup(this);
            alignmentGroup.addAction(leftAlignAct);
            alignmentGroup.addAction(rightAlignAct);
            alignmentGroup.addAction(justifyAct);
            alignmentGroup.addAction(centerAct);

        }

Once we have created the Left Align, Right Align, Justify, and a Center actions, we can also create the previously mentioned action group.

Each action is added to the group using QActionGroup's addAction() method. Note that an action also can be added to a group by creating it with the group as its parent. Since an action group is exclusive by default, only one of the actions in the group is checked at any one time (this can be altered using the QActionGroup.setExclusive() method).

When all the actions are created, we use the `createMenus()` method to add the actions to the menus and to insert the menus into the menu bar:

        void createMenus() {
            fileMenu = menuBar().addMenu(tr("&File"));
            fileMenu.addAction(newAct);
            fileMenu.addAction(openAct);
            fileMenu.addAction(saveAct);
            fileMenu.addAction(printAct);
            fileMenu.addSeparator();
            fileMenu.addAction(exitAct);

            editMenu = menuBar().addMenu(tr("&Edit"));
            editMenu.addAction(undoAct);
            editMenu.addAction(redoAct);
            editMenu.addSeparator();
            editMenu.addAction(cutAct);
            editMenu.addAction(copyAct);
            editMenu.addAction(pasteAct);
            editMenu.addSeparator();

            helpMenu = menuBar().addMenu(tr("&Help"));
            helpMenu.addAction(aboutAct);
            helpMenu.addSeparator();
            helpMenu.addAction(aboutQtJambiAct);
            helpMenu.addAction(aboutQtAct);

QMenuBar's addMenu() method appends a new QMenu with the given title, to the menubar (note that the menubar takes ownership of the menu). We use QWidget's addAction() method to add each action to the corresponding menu.

Alternatively, the QMenu class provides several addAction() convenience methods that create and add new actions from given texts and/or icons. You can also provide a member that will automatically connect to the new action's triggered() signal, and a shortcut represented by a QKeySequence instance.

The QMenu.addSeparator() method creates and returns a new separator action, i.e. an action for which QAction.isSeparator() returns true, and adds the new action to the menu's list of actions.

            formatMenu = editMenu.addMenu(tr("&Format"));
            formatMenu.addAction(boldAct);
            formatMenu.addAction(italicAct);
            formatMenu.addSeparator().setText(tr("Alignment"));
            formatMenu.addAction(leftAlignAct);
            formatMenu.addAction(rightAlignAct);
            formatMenu.addAction(justifyAct);
            formatMenu.addAction(centerAct);
            formatMenu.addSeparator();
            formatMenu.addAction(setLineSpacingAct);
            formatMenu.addAction(setParagraphSpacingAct);
        }

Note the Format menu. First of all, it is added as a submenu to the Edit Menu using QMenu's addMenu() method. Secondly, take a look at the alignment actions: In the `createActions()` method we added the `leftAlignAct`, `rightAlignAct`, `justifyAct` and `centerAct` actions to an action group. Nevertheless, we must add each action to the menu separately while the action group does its magic behind the scene.

        public void contextMenuEvent(QContextMenuEvent event) {
            QMenu menu = new QMenu(this);
            menu.addAction(cutAct);
            menu.addAction(copyAct);
            menu.addAction(pasteAct);
            menu.exec(event.globalPos());
        }

To provide a custom context menu, we must reimplement QWidget's contextMenuEvent() method to receive the widget's context menu events (note that the default implementation simply ignores these events).

Whenever we receive such an event, we create a menu containing the Cut, Copy and Paste actions. Context menus can be executed either asynchronously using the popup() method or synchronously using the exec() method. In this example, we have chosen to show the menu using its exec() method. By passing the event's position as argument we ensure that the context menu appears at the expected position.

        public static void main(String args[]) {
            QApplication.initialize(args);
            Menus menus = new Menus();
            menus.show();
            QApplication.exec();
        }

    }

Finally, we provide a `main()` method to create and show our main window when the example is run.