# System Tray Icon Example

The System Tray Icon example shows how to add an icon with a menu and popup messages, to a desktop environment's system tray.

Modern operating systems usually provide a special area on the desktop, called the system tray or notification area, where long-running applications can display icons and short messages.

## SystemTrayExample Class Implementation

The SystemTrayExample class extends QWidget and provides an editor for the system tray icon.

        public class SystemTrayExample extends QWidget {

            private QSystemTrayIcon trayIcon;
            private QMenu trayIconMenu;

            private QLineEdit titleEdit;
            private QTextEdit messageEdit;
            private QComboBox typeCombo;

            private QTextEdit infoDisplay;
            private QComboBox iconCombo;

The editor enables the user to modify the message title, edit the actual message and choose the message type. The information display will contain status messages for the icon. In addition, the user can select an icon of the preferred size.

When constructing the editor widget, we first check if the system tray is available on the user's desktop. If it is not, we show a message to the user:

            public SystemTrayExample() {
                this(null);
            }

            public SystemTrayExample(QWidget parent) {
                super(parent);
                if (!QSystemTrayIcon.isSystemTrayAvailable())
                    QMessageBox.warning(this, tr("System tray is unavailable"),
                                              tr("System tray unavailable"));

The QMessageBox class provides a modal dialog with a short message, an icon, and buttons laid out depending on the current style. It supports four severity levels: "Question", "Information", "Warning" and "Critical". The easiest way to pop up a message box in Qt is to call one of the associated static methods, e.g. QMessageBox.warning().

                trayIconMenu = new QMenu(this);
                trayIconMenu.aboutToShow.connect(this, "updateMenu()");

Then we create the menu that will appear when right-clicking over the icon in the system tray. The QMenu class provides a menu widget for use in menu bars, context menus, and other popup menus. We use the menu's aboutToShow() signal to ensure that the menu is updated when it is shown. We will come back to the editor's `updateMenu()` method later on.

A menu consists of a list of action items, i.e., a collection of QAction objects:

                toggleVisibilityAction = new QAction("Show/Hide", this);
                toggleVisibilityAction.triggered.connect(this, "toggleVisibility()");
                trayIconMenu.addAction(toggleVisibilityAction);

                QAction restoreAction = new QAction("Restore", this);
                restoreAction.triggered.connect(this, "showNormal()");
                trayIconMenu.addAction(restoreAction);

                QAction minimizeAction = new QAction("Minimize", this);
                minimizeAction.triggered.connect(this, "showMinimized()");
                trayIconMenu.addAction(minimizeAction);

                QAction maximizeAction = new QAction("Maximize", this);
                maximizeAction.triggered.connect(this, "showMaximized()");
                trayIconMenu.addAction(maximizeAction);

                trayIconMenu.addSeparator();

                QAction quitAction = new QAction("&Quit", this);
                quitAction.triggered.connect(this, "close()");
                trayIconMenu.addAction(quitAction);

The purpose of the various actions in our menu, is to control the appearance of the editor widget: Before we add each action to the menu, we connect their triggered() signal to the appropiate methods of the editor widget. The showNormal(), showMinimized(), showMaximized() and close() methods are inherited from QWidget, while the `toggleVisibility()` method is specific to this example and simply hides or shows the editor depending on its current state.

                trayIcon = new QSystemTrayIcon(this);
                trayIcon.setToolTip("System trayIcon example");
                trayIcon.setContextMenu(trayIconMenu);

                trayIcon.activated.connect(this, "activated(com.trolltech.qt.gui.QSystemTrayIcon$ActivationReason)");
                trayIcon.messageClicked.connect(this, "balloonClicked()");

                changeIcon(0);
                trayIcon.show();

It is the QSystemTrayIcon class that actually provides the icon in the system tray. When we create our icon, we first set its tooltip to be the message title and ensure that our newly created menu appears as the icon's context menu.

To provide respons to user interaction, we then connect the icon's activated() and messageClicked() signals to the editor's `activated()` and `balloonClicked()` methods, respectively. Before we show the icon, we also choose its initial size using the editor's `changeIcon()` method. We will take a look at the editor's methods shortly.

                QLabel titleLabel = new QLabel(tr("Message Title"));
                titleEdit = new QLineEdit(tr("Message Title"));

                QLabel messageLabel = new QLabel(tr("Message Contents"));
                messageEdit = new QTextEdit(tr("Man is more ape than many of the apes"));
                messageEdit.setAcceptRichText(false);

                QLabel typeLabel = new QLabel(tr("Message Type"));
                typeCombo = new QComboBox();
                Vector<String> types = new Vector<String>();
                types.add("NoIcon");
                types.add("Information");
                types.add("Warning");
                types.add("Critical");
                typeCombo.addItems(types);
                typeCombo.setCurrentIndex(2);

                QPushButton balloonButton = new QPushButton(tr("Balloon message"));
                balloonButton.setToolTip(tr("Click here to balloon the message"));
                balloonButton.clicked.connect(this, "showMessage()");

                infoDisplay = new QTextEdit(tr("Status messages will be visible here"));
                infoDisplay.setMaximumHeight(100);

                QCheckBox toggleIconCheckBox = new QCheckBox(tr("Show system tray icon"));
                toggleIconCheckBox.setChecked(true);
                toggleIconCheckBox.clicked.connect(trayIcon, "setVisible(boolean)");

                QLabel iconLabel = new QLabel("Select icon");
                iconCombo = new QComboBox();
                Vector<String> icons = new Vector<String>();
                icons.add("16x16 icon");
                icons.add("22x22 icon");
                icons.add("32x32 icon");
                iconCombo.addItems(icons);
                iconCombo.activatedIndex.connect(this, "changeIcon(int)");

                QGridLayout layout = new QGridLayout();
                layout.addWidget(titleLabel, 0, 0);
                layout.addWidget(titleEdit, 0, 1);
                layout.addWidget(messageLabel, 1, 0);
                layout.addWidget(messageEdit, 1, 1);
                layout.addWidget(typeLabel, 2, 0);
                layout.addWidget(typeCombo, 2, 1);
                layout.addWidget(balloonButton, 4, 1);
                layout.addWidget(infoDisplay, 5, 0, 1, 2);
                layout.addWidget(toggleIconCheckBox, 6, 0);
                layout.addWidget(iconLabel, 7, 0);
                layout.addWidget(iconCombo, 7, 1);
                setLayout(layout);

                setWindowTitle(tr("System Tray Example"));
                setWindowIcon(new QIcon("classpath:com/trolltech/classpath:com/trolltech/images/qt-logo.png"));
            }

Finally, we create the editor's various window elements and use a QGridLayout to organize them. The QGridLayout class takes the space made available to it, divides it up into rows and columns, and puts each widget it manages into the correct cell.

            public void closeEvent(QCloseEvent e) {

            }

It is important to note that QObject subclasses normally have a lifetime beyond what is visible to the garbage collector. To ensure that such a object is deleted, you must either assign the object to a parent (child widgets are automatically disposed of by their parents upon destruction) or call the `dispose()` method explicitly.

Since we use the QSystemTrayIcon class (which is a QObject subclass) without giving our icon a parent, we must reimplement QWidget's closeEvent() method to dispose the icon when the application is terminated.

            protected void updateMenu() {
                toggleVisibilityAction.setText(isVisible() ? tr("Hide") : tr("Show"));
            }

The `updateMenu()` method is called whenever the system tray icon's context menu is about to be shown, i.e. when the user right-clicks the icon in the system tray. The method simply checks whether the editor widget is currently visible or not, and update the menu accordingly.

            protected void toggleVisibility() {
                if (isVisible())
                    hide();
                else
                    show();
            }

The `toggleVisibility()` method is called whenever the user chooses Hide or Show in the context menu, and use the hide() and show() methods inherited from QWidget to control the appearance of the editor widget.

            protected void showMessage() {
                if (QSysInfo.macVersion() != 0) {
                    QMessageBox.information(this, tr("System tray example"),
                            tr("Balloon tips are not supported on Mac OS X"));
                } else {
                    QSystemTrayIcon.MessageIcon icon;
                    icon = QSystemTrayIcon.MessageIcon.resolve(typeCombo.currentIndex());
                    trayIcon.showMessage(titleEdit.text(), messageEdit.toPlainText(),
                                         icon, 10000);
                    trayIcon.setToolTip(titleEdit.text());
                }
            }

The `showMessage()` method is called whenever the user presses the Balloon message button. Note that balloon tips are not supported on Mac OS X. On any other platform, we create a message icon (i.e., the icon that is shown next to the message title when a balloon message is displayed), show the message and update the icon's tooltip.

            protected void balloonClicked() {
                infoDisplay.append(tr("Balloon message was clicked"));
            }

The `balloonClicked()` method is called whenever the user clicks the system tray icon's message, and simply append a status message to the information display in the editor.

            public void activated(QSystemTrayIcon.ActivationReason reason) {
                String name = QSystemTrayIcon.MessageIcon.resolve(reason.value()).name();
                if (name != null)
                    infoDisplay.append("Activated - Reason " + name);
            }

Whenever the user activates the system tray icon, e.g., by clicking it, the icon's activated() signal is emitted and the editor's `activated()` method is called (due to the connection we created in the constructor). The `activated()` method determines the reason the icon was activated and derives a corresponding message that it append to the information display in the editor.

            protected void changeIcon(int index) {
                String iconName;
                switch (index) {
                default:
                case 0:
                    iconName = "classpath:com/trolltech/examples/classpath:com/trolltech/images/icon_16x16.png";
                    break;

                case 1:
                    iconName = "classpath:com/trolltech/examples/classpath:com/trolltech/images/icon_22x22.png";
                    break;

                case 2:
                    iconName = "classpath:com/trolltech/examples/classpath:com/trolltech/images/icon_32x32.png";
                    break;
                }
                QPixmap pixmap = new QPixmap(iconName);
                trayIcon.setIcon(new QIcon(pixmap));
            }

The `changeIcon()` method is used to change the icon pixmap, and is called whenever the user select a different size for the system tray icon.

            public static void main(String[] args) {
                QApplication.initialize(args);

                SystemTrayExample editor = new SystemTrayExample();
                editor.show();

                QApplication.exec();
            }
        }

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