Beim Übersetzen der Anwendungsoberfläche von Qt/C++ nach Qt/QML gerieten meine Hände an das Anwendungssymbol in der Taskleiste. Die Aufgabe bestand darin, das Icon im System Tray von C++ nach Qml teilweise oder komplett zu übertragen. Die erste Option, die ich implementiert habe, war ein Wrapper um QSystemTrayIcon mit QMenu unter Verwendung von signal and slot system . Die Lösung ist ziemlich logisch, da es in QML kein vorgefertigtes Objekt wie MenuBar für System Tray gibt. Daher erstellen wir einen Wrapper, mit dem aus der QML -Schicht interagiert werden kann.
Nachdem der Wrapper implementiert war, hatte ich Gelegenheit, mich mit einem Programmierer von Wargamming Konstantin Lyashkevich zu beraten, der mir empfahl, auch auf die Tatsache, dass * QML nicht nur auf Signale und Slots zugreifen kann, sondern auch auf die Parameter Q_PROPERTY , die ebenfalls in der Klasse QSystemTrayIcon enthalten waren, war eigentlich nur möglich diese Klasse als Typ in der QML -Schicht zu registrieren und zu versuchen, fast den gesamten Code in QML zu schreiben. Ich habe diesen Ratschlag getestet und Konstantin das Ergebnis mitgeteilt. Infolgedessen interessierte er sich selbst für diese Aufgabe und wir verbrachten die Abendstunde mit unterhaltsamer Kalkulation und stopften in gemeinsamer Anstrengung QSystemTrayIcon so viel wie möglich in QML. *
Daher sehen Sie in diesem Artikel zwei Implementierungen für die Arbeit mit dem Taskleistensymbol.
Die resultierende Anwendung wird durch Klicken auf das Taskleistensymbol sowie durch Drücken der Schaltfläche zum Schließen des Fensters auf System Tray minimiert. Aber nur wenn ein spezielles Kontrollkästchen aktiv ist, um den Vorgang des Minimierens des Anwendungsfensters in den Tray zu steuern, wird die Anwendung geschlossen, wenn das Kontrollkästchen nicht aktiv ist. Die Anwendung kann auch geschlossen werden, wenn das Kontrollkästchen über den Menüpunkt im Taskleistensymbol aktiv ist.
Erste Wahl
Eine Option zum Arbeiten mit der Taskleiste über eine Wrapper-Klasse.
Projektstruktur für die Arbeit mit System Tray
Das Projekt enthält die folgenden Dateien:
- QmlSystemTray.pro - Projektprofil;
- main.cpp - Hauptquellcodedatei zum Ausführen der Anwendung;
- systemtray.h - Klassen-Header-Datei für die Arbeit mit dem Systemtray;
- systemtray.cpp - Klassenquellcodedatei für die Arbeit mit dem Systemtray;
- main.qml - Datei mit dem Hauptanwendungsfenster;
- logo-min.png - jedes Symbol, das in der Taskleiste platziert wird.
QmlSystemTray.pro
TEMPLATE = app QT += qml quick widgets SOURCES += main.cpp \ systemtray.cpp RESOURCES += qml.qrc # Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = # Default rules for deployment. include(deployment.pri) HEADERS += \ systemtray.h
main.cpp
Wie in der Lektion über Signale und Slots deklarieren und initialisieren wir ein Objekt einer separaten Qt / C++ -Klasse und setzen den Zugriff darauf von der Qml. -Schicht
#include <QApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QSystemTrayIcon> #include <systemtray.h> int main(int argc, char *argv[]) { QApplication app(argc, argv); QQmlApplicationEngine engine; // Объявляем и инициализируем объекта класса для работы с системным треем SystemTray * systemTray = new SystemTray(); QQmlContext * context = engine.rootContext(); // Устанавливаем доступ к свойствам объекта класса в контексте QML context->setContextProperty("systemTray", systemTray); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
systemtray.h
In der Header-Datei der SystemTray -Klasse deklarieren wir die Signale, die Informationen an QML übergeben, sowie das QSystemTrayIcon -Objekt, mit dem die Interaktion durchgeführt wird. Außerdem deklarieren wir mit diesem Icon einen Interaktionshandler.
#ifndef SYSTEMTRAY_H #define SYSTEMTRAY_H #include <QObject> #include <QAction> #include <QSystemTrayIcon> class SystemTray : public QObject { Q_OBJECT public: explicit SystemTray(QObject *parent = 0); // Сигналы от системного трея signals: void signalIconActivated(); void signalShow(); void signalQuit(); private slots: /* Слот, который будет принимать сигнал от события * нажатия на иконку приложения в трее */ void iconActivated(QSystemTrayIcon::ActivationReason reason); public slots: void hideIconTray(); private: /* Объявляем объект будущей иконки приложения для трея */ QSystemTrayIcon * trayIcon; }; #endif // SYSTEMTRAY_H
systemtray.cpp
Als Nächstes schreiben wir den Klassenquellcode für die Arbeit mit System Tray , aber wir implementieren die Signalisierung nur bei der Interaktion mit Menüelementen und dem Symbol in der Taskleiste. Signalverarbeitungslogik wird in QML implementiert.
#include "systemtray.h" #include <QMenu> #include <QSystemTrayIcon> SystemTray::SystemTray(QObject *parent) : QObject(parent) { // Создаём контекстное меню с двумя пунктами QMenu *trayIconMenu = new QMenu(); QAction * viewWindow = new QAction(trUtf8("Развернуть окно"), this); QAction * quitAction = new QAction(trUtf8("Выход"), this); /* подключаем сигналы нажатий на пункты меню к соответсвующим сигналам для QML. * */ connect(viewWindow, &QAction::triggered, this, &SystemTray::signalShow); connect(quitAction, &QAction::triggered, this, &SystemTray::signalQuit); trayIconMenu->addAction(viewWindow); trayIconMenu->addAction(quitAction); /* Инициализируем иконку трея, устанавливаем иконку, * а также задаем всплывающую подсказку * */ trayIcon = new QSystemTrayIcon(); trayIcon->setContextMenu(trayIconMenu); trayIcon->setIcon(QIcon(":/logo-min.png")); trayIcon->show(); trayIcon->setToolTip("Tray Program" "\n" "Работа со сворачиванием программы трей"); /* Также подключаем сигнал нажатия на иконку к обработчику * данного нажатия * */ connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); } /* Метод, который обрабатывает нажатие на иконку приложения в трее * */ void SystemTray::iconActivated(QSystemTrayIcon::ActivationReason reason) { switch (reason){ case QSystemTrayIcon::Trigger: // В случае сигнала нажатия на иконку трея вызываем сигнал в QML слой emit signalIconActivated(); break; default: break; } } void SystemTray::hideIconTray() { trayIcon->hide(); }
main.qml
Um auf die Eigenschaften des SystemTray -Klassenobjekts im Qml -Layer zuzugreifen, schreiben wir das Connections -Objekt, über das die Verbindung zum SystemTray-Objekt hergestellt wird. in das Target -Eigenschaft schreiben wir den Namen, der in der Datei main.cpp deklariert wurde, als die Qml -Engine über die setContextProperty()-Methode auf das Taskleistenobjekt zugegriffen hat.
import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Window 2.0 ApplicationWindow { id: application visible: true width: 640 height: 480 title: qsTr("Hello World") // Переменная для игнорирования чекбокса property bool ignoreCheck: false /* С помощью объекта Connections * Устанавливаем соединение с классом системного трея * */ Connections { target: systemTray // Сигнал - показать окно onSignalShow: { application.show(); } // Сигнал - закрыть приложения игнорируя чек-бокс onSignalQuit: { ignoreCheck = true close(); } // Свернуть/развернуть окно через клик по системному трею onSignalIconActivated: { if(application.visibility === Window.Hidden) { application.show() } else { application.hide() } } } // Тестовый чекбокс для управления закрытием окна CheckBox { id: checkTray anchors.centerIn: parent text: qsTr("Включить сворачивание в системный трей при нажатии кнопки закрытия окна") } // Обработчик события закрытия окна onClosing: { /* Если чекбокс не должен игнорироваться и он активен, * то скрываем приложение. * В противном случае закрываем приложение * */ if(checkTray.checked === true && ignoreCheck === false){ close.accepted = false application.hide() } else { // Завершаем приложение Qt.quit() } } }
Zweite Option
Kommen wir nun zur zweiten Implementierungsoption, die in Zusammenarbeit mit Konstantin Lyashkevich geschrieben wurde.
Projektstruktur
In diesem Fall besteht die Projektstruktur nur aus:
- QmlSystemTray.pro - Projektprofil;
- main.cpp - Hauptquellcodedatei zum Ausführen der Anwendung;
- main.qml - Datei mit dem Hauptanwendungsfenster;
- logo-min.png - jedes Symbol, das in der Taskleiste platziert wird.
QmlSystemTray_2.pro
In diesem Fall empfehle ich, auf die Module zu achten, die im Projekt verbunden sind. Denn auf das Modul quickwidgets kann man nicht verzichten.
TEMPLATE = app QT += qml quick widgets quickwidgets SOURCES += main.cpp RESOURCES += qml.qrc # Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = # Default rules for deployment. include(deployment.pri)
main.cpp
Außerdem muss die Bibliothek QQuickWidget in die Quelldatei main.cpp. aufgenommen werden. Dies ist erforderlich, um die Funktion qmlRegisterType. zu verwenden.
#include <QApplication> #include <QQmlApplicationEngine> #include <QIcon> #include <QQuickWidget> #include <QSystemTrayIcon> #include <QQmlContext> // Объявляем пользовательский тип данных для работы с иконкой в QML Q_DECLARE_METATYPE(QSystemTrayIcon::ActivationReason) int main(int argc, char *argv[]) { QApplication app(argc, argv); QQmlApplicationEngine engine; // Инициализируем Qml движок // Регистрируем QSystemTrayIcon в качестве типа объекта в Qml qmlRegisterType<QSystemTrayIcon>("QSystemTrayIcon", 1, 0, "QSystemTrayIcon"); // Регистрируем в QML тип данных для работы с получаемыми данными при клике по иконке qRegisterMetaType<QSystemTrayIcon::ActivationReason>("ActivationReason"); // Устанавливаем Иконку в контекст движка engine.rootContext()->setContextProperty("iconTray", QIcon(":/logo-min.png")); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
main.qml
Als Nächstes deklarieren wir das Objekt QSystemTrayIcon und richten es in der Methode onCompleted des übergebenen Werts reason ein, um die Reaktion auf Mausklicks auf das Anwendungssymbol in der Taskleiste zu bestimmen. Wenn wir mit der rechten Maustaste auf das Anwendungssymbol in der Taskleiste klicken, erscheint Menü. Das Menü wird von der Funktion popup() aufgerufen. Das Merkmal der Funktion ist, dass sie das Menü an der Stelle aufruft wo sich der Mauszeiger befindet , sodass das Menü an der Stelle des Taskleistensymbols angezeigt wird.
import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Window 2.0 import QSystemTrayIcon 1.0 ApplicationWindow { id: application visible: true width: 640 height: 480 title: qsTr("Hello World") // Зарегистрированный системный трей в QML слое QSystemTrayIcon { id: systemTray // Первоначальная инициализация системного трея Component.onCompleted: { icon = iconTray // Устанавливаем иконку // Задаём подсказку для иконки трея toolTip = "Tray Program Работа со сворачиванием программы трей" show(); } /* По клику на иконку трея определяем, * левой или правой кнопкой мыши был клик. * Если левой, то скрываем или открываем окно приложения. * Если правой, то открываем меню системного трея * */ onActivated: { if(reason === 1){ trayMenu.popup() } else { if(application.visibility === Window.Hidden) { application.show() } else { application.hide() } } } } // Меню системного трея Menu { id: trayMenu MenuItem { text: qsTr("Развернуть окно") onTriggered: application.show() } MenuItem { text: qsTr("Выход") onTriggered: { systemTray.hide() Qt.quit() } } } // Тестовый чекбокс для управления закрытием окна CheckBox { id: checkTray anchors.centerIn: parent text: qsTr("Включить сворачивание в системный трей при нажатии кнопки закрытия окна") } // Обработчик события закрытия окна onClosing: { /* Если чекбокс не должен игнорироваться и он активен, * то скрываем приложение. * В противном случае закрываем приложение * */ if(checkTray.checked === true){ close.accepted = false application.hide() } else { // Завершаем приложение Qt.quit() } } }
Insgesamt
Als Ergebnis der geleisteten Arbeit erhalten Sie eine Anwendung, die sowohl durch Klicken auf das Symbol in der Taskleiste als auch durch Drücken der Schaltfläche zum Schließen des Anwendungsfensters in die Taskleiste minimiert wird. Es wird wie auf dem Bild unten aussehen. Nun, Sie können eine Demonstration der Anwendung im Video-Tutorial sehen, das beide Optionen für den Programmcode erklärt.
Mitautor des Artikels: Konstantin Lyashkevich
Здравствуйте. В первом варианте не выложен файл QmlSystemTray.pro без него как-то не полно.
Добрый день. Добавил QmlSystemTray.pro.
Спасибо)