Evgenii Legotckoi
Nov. 1, 2015, 11:39 p.m.

QML - Lesson 008. How to work with system tray (QSystemTrayIcon)

When moving the application interface from Qt / C ++ to Qt / QML my hands reached and application icons in the system tray. The aim was to put an icon in the System Tray from C ++ to QML, partially or completely. The first option, which I realized, was a wrapper around QSystemTrayIcon with QMenu using a system of signals and slots . The solution is quite logical, given that in QML is not a facility, like MenuBar to System Tray. So we do a wrapper, which can interact in QML layer.

After the wrapper was implemented, I had the opportunity to consult with the programmer of Wargamming  - Constantine Lyashkevich , who recommended me to pay attention to what QML can have access not only to the signals and slots, and the parameters of the Q_PROPERTY , who also were in the class QSystemTrayIcon , that is, in fact it was only possible to register this class as the type layer in QML and try to write almost all the code on the QML. I checked the board and talked about by Constantine. As a result, he became interested in this problem and we spent the evening entertaining hour of attempts and jointly stuffed QSystemTrayIcon maximum in QML.

So in this article you will see two implementations to work with an icon in the system tray.

The resulting application will minimize to the System Tray by clicking the icon in the system tray, as well as by pressing the close button. But only in the event that will be active the special checkbox to control the folding process of the application window to the system tray, if the checkbox is not enabled, the application will be closed. Also, the application can be closed with an active checkbox menu item in the system tray icon.


First variant

Variant to work with the system tray through the wrapper class.

Projeect structure for System Tray

The project includes the following files:

  • QmlSystemTray.pro - the profile of the project;
  • main.cpp - the primary source file to launch the application;
  • systemtray.h - class header file to work with the system tray;
  • systemtray.cpp - class source code file to work with the system tray;
  • main.qml - file from the main application window;
  • logo-min.png - any icon that will be placed in the system tray.

QmlSystemTray.pro

  1. TEMPLATE = app
  2.  
  3. QT += qml quick widgets
  4.  
  5. SOURCES += main.cpp \
  6. systemtray.cpp
  7.  
  8. RESOURCES += qml.qrc
  9.  
  10. # Additional import path used to resolve QML modules in Qt Creator's code model
  11. QML_IMPORT_PATH =
  12.  
  13. # Default rules for deployment.
  14. include(deployment.pri)
  15.  
  16. HEADERS += \
  17. systemtray.h

main.cpp

As in the tutorial on signals and slots make the declaration and initialization of the object of a separate Qt / C ++ class and set the access to it from Qml layer.

  1. #include <QApplication>
  2. #include <QQmlApplicationEngine>
  3. #include <QQmlContext>
  4. #include <QSystemTrayIcon>
  5.  
  6. #include <systemtray.h>
  7.  
  8. int main(int argc, char *argv[])
  9. {
  10. QApplication app(argc, argv);
  11.  
  12. QQmlApplicationEngine engine;
  13.  
  14. // We declare and initialize the class object to work with system tray
  15. SystemTray * systemTray = new SystemTray();
  16. QQmlContext * context = engine.rootContext();
  17. // Set access to an object of class properties in QML context
  18. context->setContextProperty("systemTray", systemTray);
  19.  
  20. engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
  21.  
  22. return app.exec();
  23. }

systemtray.h

The header file declares the class SystemTray signals that will pass information to the QML, and QSystemTrayIcon object that will be interaction. In addition, we declare a handler interact with this icon.

  1. #ifndef SYSTEMTRAY_H
  2. #define SYSTEMTRAY_H
  3.  
  4. #include <QObject>
  5. #include <QAction>
  6. #include <QSystemTrayIcon>
  7.  
  8. class SystemTray : public QObject
  9. {
  10. Q_OBJECT
  11. public:
  12. explicit SystemTray(QObject *parent = 0);
  13.  
  14. signals:
  15. void signalIconActivated();
  16. void signalShow();
  17. void signalQuit();
  18.  
  19. private slots:
  20. /* The slot that will accept the signal from the event click on the application icon in the system tray
  21. */
  22. void iconActivated(QSystemTrayIcon::ActivationReason reason);
  23.  
  24. public slots:
  25. void hideIconTray();
  26.  
  27. private:
  28. /* Declare the object of future applications for the tray icon*/
  29. QSystemTrayIcon * trayIcon;
  30. };
  31.  
  32. #endif // SYSTEMTRAY_H

systemtray.cpp

Next we writes the source code for the class to work with System Tray, but realize only supply signals in the interaction with the menu items and the system tray icon. the signal processing logic is implemented in QML.

  1. #include "systemtray.h"
  2. #include <QMenu>
  3. #include <QSystemTrayIcon>
  4.  
  5. SystemTray::SystemTray(QObject *parent) : QObject(parent)
  6. {
  7.  
  8. // Create a context menu with two items
  9. QMenu *trayIconMenu = new QMenu();
  10.  
  11. QAction * viewWindow = new QAction(trUtf8("Развернуть окно"), this);
  12. QAction * quitAction = new QAction(trUtf8("Выход"), this);
  13.  
  14. /* to connect the signals clicks on menu items to the appropriate signals for QML.
  15. * */
  16. connect(viewWindow, &QAction::triggered, this, &SystemTray::signalShow);
  17. connect(quitAction, &QAction::triggered, this, &SystemTray::signalQuit);
  18.  
  19. trayIconMenu->addAction(viewWindow);
  20. trayIconMenu->addAction(quitAction);
  21.  
  22. /* Initialize the tray icon, icon set, and specify the tooltip
  23. * */
  24. trayIcon = new QSystemTrayIcon();
  25. trayIcon->setContextMenu(trayIconMenu);
  26. trayIcon->setIcon(QIcon(":/logo-min.png"));
  27. trayIcon->show();
  28. trayIcon->setToolTip("Tray Program" "\n"
  29. "Work with winimizing program to tray");
  30.  
  31. /* Also connect clicking on the icon to the signal handler of the pressing
  32. * */
  33. connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
  34. this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
  35. }
  36.  
  37. /* The method that handles click on the application icon in the system tray
  38. * */
  39. void SystemTray::iconActivated(QSystemTrayIcon::ActivationReason reason)
  40. {
  41. switch (reason){
  42. case QSystemTrayIcon::Trigger:
  43. // In the case of pressing the signal on the icon tray in the call signal QML layer
  44. emit signalIconActivated();
  45. break;
  46. default:
  47. break;
  48. }
  49. }
  50.  
  51. void SystemTray::hideIconTray()
  52. {
  53. trayIcon->hide();
  54. }

main.qml

To access the properties of an object of the class SystemTray in the Qml layer prescribes object Connections, through which the connection to SystemTray object. to prescribe target property name, which was announced in the main.cpp file, when the engine is installed Qml access to the object through the system tray setContextProperty() method.

  1. import QtQuick 2.5
  2. import QtQuick.Controls 1.4
  3. import QtQuick.Window 2.0
  4.  
  5. ApplicationWindow {
  6. id: application
  7. visible: true
  8. width: 640
  9. height: 480
  10. title: qsTr("Hello World")
  11.  
  12. // Chance to ignore the checkbox
  13. property bool ignoreCheck: false
  14.  
  15. /* With help Connections object
  16. * set connections with System tray class
  17. * */
  18. Connections {
  19. target: systemTray
  20. // Сигнал - показать окно
  21. onSignalShow: {
  22. application.show();
  23. }
  24.  
  25. // The signal - close the application by ignoring the check-box
  26. onSignalQuit: {
  27. ignoreCheck = true
  28. close();
  29. }
  30.  
  31. // Minimize / maximize the window by clicking on the default system tray
  32. onSignalIconActivated: {
  33. if(application.visibility === Window.Hidden) {
  34. application.show()
  35. } else {
  36. application.hide()
  37. }
  38. }
  39. }
  40.  
  41. // Test check box to control the closing of the window
  42. CheckBox {
  43. id: checkTray
  44. anchors.centerIn: parent
  45. text: qsTr("Enable minimizing to system tray during the window closing")
  46. }
  47.  
  48. // Handler window closing event
  49. onClosing: {
  50. /* If the check box should not be ignored and it is active,
  51.   * then hide the application. Otherwise, close the application
  52. * */
  53. if(checkTray.checked === true && ignoreCheck === false){
  54. close.accepted = false
  55. application.hide()
  56. } else {
  57. Qt.quit()
  58. }
  59. }
  60. }

Second variant

And now proceed to the second embodiment, which is written in collaboration with Konstantin Lyashkevich.

Project Structure

In this case, only the structure of the project will consist of:

  • QmlSystemTray.pro - the profile of the project;
  • main.cpp - the primary source file to launch the application;
  • main.qml - file of the main application window;
  • logo-min.png - any icon that will be placed in the system tray.

QmlSystemTray_2.pro

In this case, I recommend to pay attention to the modules that are connected in the project. Because without quickwidgets module do not work.

  1. TEMPLATE = app
  2.  
  3. QT += qml quick widgets quickwidgets
  4.  
  5. SOURCES += main.cpp
  6.  
  7. RESOURCES += qml.qrc
  8.  
  9. # Additional import path used to resolve QML modules in Qt Creator's code model
  10. QML_IMPORT_PATH =
  11.  
  12. # Default rules for deployment.
  13. include(deployment.pri)

main.cpp

It is also necessary to connect the library to the QQuickWidget main.cpp source file. It is necessary to use qmlRegisterType function.

  1. #include <QApplication>
  2. #include <QQmlApplicationEngine>
  3. #include <QIcon>
  4. #include <QQuickWidget>
  5. #include <QSystemTrayIcon>
  6. #include <QQmlContext>
  7.  
  8. // Declare a user-defined data type to work with an icon in QML
  9. Q_DECLARE_METATYPE(QSystemTrayIcon::ActivationReason)
  10.  
  11. int main(int argc, char *argv[])
  12. {
  13. QApplication app(argc, argv);
  14. QQmlApplicationEngine engine;
  15.  
  16. // Register QSystemTrayIcon in Qml
  17. qmlRegisterType<QSystemTrayIcon>("QSystemTrayIcon", 1, 0, "QSystemTrayIcon");
  18. // Register in QML the data type of click by tray icon
  19. qRegisterMetaType<QSystemTrayIcon::ActivationReason>("ActivationReason");
  20. // Set icon in the context of the engine
  21. engine.rootContext()->setContextProperty("iconTray", QIcon(":/logo-min.png"));
  22. engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
  23.  
  24. return app.exec();
  25. }

main.qml

Next, we make declaring QSystemTrayIcon object and configure it in onCompleted method. Due to the fact that we have registered the type QSystemTrayIcon::ActivationReason, then the method onActivated we are able, depending on the type of value sent is reason to determine the response to mouse clicks on an application icon in the system tray. When we do a right click on the application icon in the system tray, there is a Menu . The menu is a function popup() . function feature is that it brings up a menu at the point where the mouse cursor, so the menu appears at the location of the system tray icons.

  1. import QtQuick 2.5
  2. import QtQuick.Controls 1.4
  3. import QtQuick.Window 2.0
  4. import QSystemTrayIcon 1.0
  5.  
  6. ApplicationWindow {
  7. id: application
  8. visible: true
  9. width: 640
  10. height: 480
  11. title: qsTr("Hello World")
  12.  
  13. // Registered in the system tray QML layer
  14. QSystemTrayIcon {
  15. id: systemTray
  16.  
  17. // Initial initialization of the system tray
  18. Component.onCompleted: {
  19. icon = iconTray // Set icon
  20. toolTip = "Tray Program
  21. Работа со сворачиванием программы трей"
  22. show();
  23. }
  24.  
  25. /* By clicking on the tray icon define the left or right mouse button click was.
  26.   * If left, then hide or open the application window.
  27.   * If right, then open the System Tray menu
  28. * */
  29. onActivated: {
  30. if(reason === 1){
  31. trayMenu.popup()
  32. } else {
  33. if(application.visibility === Window.Hidden) {
  34. application.show()
  35. } else {
  36. application.hide()
  37. }
  38. }
  39. }
  40. }
  41.  
  42. // Menu system tray
  43. Menu {
  44. id: trayMenu
  45.  
  46. MenuItem {
  47. text: qsTr("Maximize window")
  48. onTriggered: application.show()
  49. }
  50.  
  51. MenuItem {
  52. text: qsTr("Exit")
  53. onTriggered: {
  54. systemTray.hide()
  55. Qt.quit()
  56.  
  57. }
  58. }
  59. }
  60.  
  61. // Test check box to control the closing of the window
  62. CheckBox {
  63. id: checkTray
  64. anchors.centerIn: parent
  65. text: qsTr("Enable minimizing to system tray during the closing the window")
  66. }
  67. onClosing: {
  68. /* If the check box should not be ignored and it is active, then hide the application.
  69.   * Otherwise, close the application
  70. * */
  71. if(checkTray.checked === true){
  72. close.accepted = false
  73. application.hide()
  74. } else {
  75. Qt.quit()
  76. }
  77. }
  78. }

Conclusion

As a result of the work done, you will receive an application, which will be minimized to tray as the clicks on the icon in the system tray, and close the window by pressing the application button. Look, it would be like in the following figure.

Co-author of the article: Constantine Lyashkevich

Video

Do you like it? Share on social networks!

o
  • April 4, 2017, 3:13 a.m.

Здравствуйте. В первом варианте не выложен файл QmlSystemTray.pro без него как-то не полно.

Evgenii Legotckoi
  • April 4, 2017, 12:33 p.m.

Добрый день. Добавил QmlSystemTray.pro.

o
  • April 4, 2017, 12:34 p.m.

Спасибо)

Comments

Only authorized users can post comments.
Please, Log in or Sign up
  • Last comments
  • Evgenii Legotckoi
    March 9, 2025, 9:02 p.m.
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    March 9, 2025, 4:14 p.m.
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
  • ИМ
    Nov. 22, 2024, 9:51 p.m.
    Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
  • Evgenii Legotckoi
    Oct. 31, 2024, 11:37 p.m.
    Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
  • A
    Oct. 19, 2024, 5:19 p.m.
    Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html