Ein ähnlicher Artikel zu PyQt5 / Python
Heute werden wir besprechen, wie eine im Qt-Framework geschriebene Anwendung mithilfe der Klasse QSystemTrayIcon in die Taskleiste des Betriebssystems minimiert werden kann. Diese Funktion ist sehr nützlich für Anwendungen, die längere Zeit im Hintergrund laufen müssen. Zum Beispiel eine Anwendung zur Videoaufnahme oder Audiowiedergabe.
Daher beschäftigen wir uns mit folgenden Fragen:
- Wie Sie Ihrem Programm beibringen, in das Fach zu minimieren;
- So erstellen Sie ein Kontextmenü für das Tray-Icon Ihrer Anwendung;
- So deaktivieren Sie diese Funktion, wenn sie nicht erforderlich ist.
Der Programmcode wurde in QtCreator 3.3.1 basierend auf Qt 5.4.1 geschrieben.
Projektstruktur für QSystemTrayIcon
Das Projekt wird als Qt Widgets-Anwendung erstellt, in der die Dateien standardmäßig erstellt werden:
- Tray.pro - Profil;
- mainwindow.h - Header-Datei des Hauptanwendungsfensters;
- mainwindow.cpp - Fensterquellcode;
- main.cpp - die Hauptquelldatei, von der aus die Anwendung startet;
- mainwindow.ui - die Form des Hauptanwendungsfensters.
Notiz. Ich erstelle den größten Teil der Benutzeroberfläche im Designer, um die Logik des Hauptcodes nicht mit unnötigen Informationen zu überladen. Tatsächlich ist dies nur eine Frage des Geschmacks und der Gewohnheit.
mainwindow.ui
Fensterform zum Prüfen des Trays Zum Test erstellen wir eine einfache und unauffällige Form mit Checkbox.
Der Name des QCheckBox-Objekts lautet wie folgt - trayCheckBox
Tray.pro
Wir belassen diese Datei mit den Standardeinstellungen.
#------------------------------------------------- # # Project created by QtCreator 2015-08-10T17:18:30 # #------------------------------------------------- QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = Tray TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp HEADERS += mainwindow.h FORMS += mainwindow.ui
main.cpp
Auch diese Datei unterliegt keinen Änderungen.
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
mainwindow.h
In der Header-Datei werden bereits Änderungen vorgenommen, da wir das Ereignis zum Schließen des Fensters nachverfolgen und einen Handler für Klicks auf das Anwendungssymbol in der Taskleiste erstellen müssen. Vergessen Sie auch nicht, in dieser Datei alle erforderlichen Bibliotheken aufzunehmen. Andernfalls wird das Projekt nicht kompiliert.
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QCloseEvent> #include <QSystemTrayIcon> #include <QAction> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); protected: /* Виртуальная функция родительского класса в нашем классе * переопределяется для изменения поведения приложения, * чтобы оно сворачивалось в трей, когда мы этого хотим */ void closeEvent(QCloseEvent * event); private slots: /* Слот, который будет принимать сигнал от события * нажатия на иконку приложения в трее */ void iconActivated(QSystemTrayIcon::ActivationReason reason); private: Ui::MainWindow * ui; /* Объявляем объект будущей иконки приложения для трея */ QSystemTrayIcon * trayIcon; }; #endif // MAINWINDOW_H
mainwindow.cpp
Die gesamte Logik der zu testenden Anwendung ist in diese Klasse eingebettet. Die Anwendung wird nur dann in die Taskleiste minimiert, wenn das Kontrollkästchen aktiviert ist. Anstelle eines Kontrollkästchens kann eine Variable oder eine andere Möglichkeit zum Speichern von Informationen über die Notwendigkeit, dass diese Funktion funktioniert, wirken.
Anwendungssymbol in der Taskleiste mit Kontextmenü In diesem Fall wird zum Beenden der Anwendung bei aktiviertem Kontrollkästchen der entsprechende Eintrag im Kontextmenü verwendet.
Auch wenn die Anwendung in den Tray minimiert wird, wird eine entsprechende Meldung angezeigt, die den Benutzer über dieses Ereignis informiert.
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); this->setWindowTitle("Tray Program"); /* Инициализируем иконку трея, устанавливаем иконку из набора системных иконок, * а также задаем всплывающую подсказку * */ trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(this->style()->standardIcon(QStyle::SP_ComputerIcon)); trayIcon->setToolTip("Tray Program" "\n" "Работа со сворачиванием программы трей"); /* После чего создаем контекстное меню из двух пунктов*/ QMenu * menu = new QMenu(this); QAction * viewWindow = new QAction(trUtf8("Развернуть окно"), this); QAction * quitAction = new QAction(trUtf8("Выход"), this); /* подключаем сигналы нажатий на пункты меню к соответсвующим слотам. * Первый пункт меню разворачивает приложение из трея, * а второй пункт меню завершает приложение * */ connect(viewWindow, SIGNAL(triggered()), this, SLOT(show())); connect(quitAction, SIGNAL(triggered()), this, SLOT(close())); menu->addAction(viewWindow); menu->addAction(quitAction); /* Устанавливаем контекстное меню на иконку * и показываем иконку приложения в трее * */ trayIcon->setContextMenu(menu); trayIcon->show(); /* Также подключаем сигнал нажатия на иконку к обработчику * данного нажатия * */ connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); } MainWindow::~MainWindow() { delete ui; } /* Метод, который обрабатывает событие закрытия окна приложения * */ void MainWindow::closeEvent(QCloseEvent * event) { /* Если окно видимо и чекбокс отмечен, то завершение приложения * игнорируется, а окно просто скрывается, что сопровождается * соответствующим всплывающим сообщением */ if(this->isVisible() && ui->trayCheckBox->isChecked()){ event->ignore(); this->hide(); QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon(QSystemTrayIcon::Information); trayIcon->showMessage("Tray Program", trUtf8("Приложение свернуто в трей. Для того чтобы, " "развернуть окно приложения, щелкните по иконке приложения в трее"), icon, 2000); } } /* Метод, который обрабатывает нажатие на иконку приложения в трее * */ void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { switch (reason){ case QSystemTrayIcon::Trigger: /* Событие игнорируется в том случае, если чекбокс не отмечен * */ if(ui->trayCheckBox->isChecked()){ /* иначе, если окно видимо, то оно скрывается, * и наоборот, если скрыто, то разворачивается на экран * */ if(!this->isVisible()){ this->show(); } else { this->hide(); } } break; default: break; } }
Ergebnis
Im Falle eines erfolgreichen Builds des Projekts wird Ihre Anwendung mit einem Kolach leicht in die Schublade geworfen. Ein Beispiel, wie die Anwendung mit QSystemTrayIcon funktioniert, zeigt das folgende Video:
И то и другое можно применить для десктопного приложения, и как лучше строить выбор?
Два примера реализации системного трея с использованием QML есть вот в этом уроке: http://www.evileg.ru/baza-znanij/qt-qml-android/rabota-s-system-tray-v-qml-qt-prilozhenii.html
Добрый день.
При попытке запуска приложения в Qt Creator 4.2.0 на Qt 5.7.1 выдаёт следующие ошибки (как при ручном вводе кода, так и при копировании с сайта):
1. В файле mainwindow.cpp :
Помогло добавление директивы
Спасибо за урок!
Видимо, когда я работал с этим кодом, QMenu подключался в заголовочнике QSystemTrayIcon , поэтому и сработало нормально. В любом случае ваше решение верное. Внесу поправку, что если у Вас нет объявлений QMenu в заголовочнике, то лучше перенеси include в cpp файл.
Спасибо! А чем ваш вариант лучше? Скажу сразу, что не совсем хорошо разбираюсь в C++ (школьная программа была пройдена, - в институте немного "подзабил")), но вроде при инклюде заголовочного файла с объявленным QMenu, например в другой .cpp, в нём тоже всё будет работать, иначе для каждого cpp-файла QMenu будет подключаться отдельно - выходит, это более оптимально?
Это к вопросу о скорости компиляции проекта. В маленьких проектах это не очень заметно, а в крупных становится очевидным.
Если всё подключать в заголовочниках, то много времени тратится на проверку того, был ли уже тот или иной заголовочник подключён в в конкретном заголовочном файле. А если стараться подключать заголовочные файлы в файле исходных кодов, то количество таких проверок снижается, соответственно уменьшается время на сборку проекта.
Также есть ещё один хороший способ увеличить скорость компиляции, если объект какого-либо класса, например того же самого QMenu объявляется как указатель в заголовочном файле, то можно объявить класс QMenu, а заголовочный файл подключить уже в файле исходных кодов.
Это будет выглядеть следующим образом:
widget.h widget.cppУ кого при компиляции ворненги - отредактируйте код таким образом, чтобы trUtf8() не было, а было просто tr()
Здравствуйте, извиняюсь за вопрос немного не по теме урока, а скорее по общему синтаксису Qt, связанному с активным использованием указателей.
В частности в вашем примере, разве new QMenu, QAction и QSystemTrayIconnew без их последующего delete не должно приводить к утечке памяти?
Добрый день!