В данном HOWTO мы подробно рассмотрим как свернуть форму приложения на Qt в системный трей на всех платформах: Windows, GNU/Linux, MacOS. Мы будем использовать только методы Qt и никаких хаков вроде вызова WinAPI функций и т.д.
Введение
Для работы мы будем использовать свободную официальную IDE для разработки на C++/Qt — Qt Creator.
Код из наших примеров корректно компилируется и работает как в Qt 4.x, так и в 5.x. Лицензия всех фрагментов кода из данной статьи — GNU General Public License version 3.
Создаём проект
Создайте новый проект на Qt: File -> New file or Project -> Application -> Qt Widgets Application. Названия и пути укажите произвольные.
Подключаем заголовочные файлы
Для начала нам потребуется подключить заголовочные файлы, которые отвечают за работу с элементом QtTray. В файлах mainwindow.h и mainwindow.cpp пропишите:
#include <QSystemTrayIcon>
В файле mainwindow.cpp также подключите (потребуются нам для создания контекстного меню иконки в трее и вывода сообщения):
#include <QMenu> #include <QMessageBox>
Работаем с заголовочными файлами
В mainwindow.h пропишите свойства и методы, которые будут использоваться в проекте:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QSystemTrayIcon> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void changeEvent(QEvent*); void trayIconActivated(QSystemTrayIcon::ActivationReason reason); void trayActionExecute(); void setTrayIconActions(); void showTrayIcon(); private: Ui::MainWindow *ui; QMenu *trayIconMenu; QAction *minimizeAction; QAction *restoreAction; QAction *quitAction; QSystemTrayIcon *trayIcon; }; #endif // MAINWINDOW_H
Добавляем значок в ресурс
В меню File — New File or Project выберите Qt — Qt Resource File.
В открывшемся редакторе создайте новый префикс кнопкой Add — Add Prefix с именем images, перейдите в него, затем загрузите изображение в формате PNG желательно с заданным альфа-каналом с именем abc.png (можно указать любое, но без пробелов и символов юникода).
Работаем с кодом
Опишите новый метод, в котором будет создан объект класса QSystemTrayIcon, заданы его свойства, добавлено простое контекстное меню и обработчик клика по значку в трее:
void MainWindow::showTrayIcon() { // Создаём экземпляр класса и задаём его свойства... trayIcon = new QSystemTrayIcon(this); QIcon trayImage(":/images/abc.png"); trayIcon -> setIcon(trayImage); trayIcon -> setContextMenu(trayIconMenu); // Подключаем обработчик клика по иконке... connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); // Выводим значок... trayIcon -> show(); }
Добавьте методы обработки кликов по иконке в системном трее:
void MainWindow::trayActionExecute() { QMessageBox::information(this, "TrayIcon", "Тестовое сообщение. Замените вызов этого сообщения своим кодом."); } void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason) { switch (reason) { case QSystemTrayIcon::Trigger: case QSystemTrayIcon::DoubleClick: this -> trayActionExecute(); break; default: break; } }
Создайте и добавьте контекстное меню для нашего значка:
void MainWindow::setTrayIconActions() { // Setting actions... minimizeAction = new QAction("Свернуть", this); restoreAction = new QAction("Восстановить", this); quitAction = new QAction("Выход", this); // Connecting actions to slots... connect (minimizeAction, SIGNAL(triggered()), this, SLOT(hide())); connect (restoreAction, SIGNAL(triggered()), this, SLOT(showNormal())); connect (quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); // Setting system tray's icon menu... trayIconMenu = new QMenu(this); trayIconMenu -> addAction (minimizeAction); trayIconMenu -> addAction (restoreAction); trayIconMenu -> addAction (quitAction); }
Теперь напишем перехватчик события сворачивания формы на панель задач и вместо этого свернём её в трей:
void MainWindow::changeEvent(QEvent *event) { QMainWindow::changeEvent(event); if (event -> type() == QEvent::WindowStateChange) { if (isMinimized()) { this -> hide(); } } }
Наше приложение практически готово. Последний штрих — отредактируйте событие инициализации формы и пропишите вызовы созданных нами методов:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui -> setupUi(this); this -> setTrayIconActions(); this -> showTrayIcon(); }
Завершение и сборка
Скомпилируйте созданное приложение и запустите. Если всё сделано правильно, в трее появится значок, при щелчке левой кнопкой мыши по которому появится сообщение, а правой — контекстное меню с тремя пунктами.
Указанные примеры кода не имеют каких-либо проверок на наличие трея в окружении (в среде Gnome например трея может не быть), восстановление значка в случае падения приложения, управляющего треем (Explorer.exe в Windows) и т.д. Это было сделано сознательно, дабы максимально упростить код.
Исходники проекта
Исходники данного демонстрационного проекта доступны на GitHub: https://github.com/xvitaly/traysample и распространяются под лицензией GNU GPL версии 3.
Вот это часть кода не очень понятна
Тут указан относительный (если я ошибаюсь) путь к картинке.
Куда бы я не загружал картинку, у меня она не выводится при запуске приложения.
Всё работает, а картинки нет. Меню выводится на «пустом месте».
Скажите пожалуйста — где должна располагаться картинка, в ОС windows?
Какие требования к png? У меня размер 32 на 32 пикселя.
Не могли бы вы более подробно расписать раздел «Добавляем значок в ресурс»
А именно имена и пути.
@Иван
Путь указывается относительно корня ресурсного файла проекта. Об этом подробно написано в «Добавляем значок в ресурс».
В ресурсном файле вы должны создать префикс images, перейти в него и залить файл abc.png. Только после этого он будет доступен по указанному в примере пути.
Размер PNG может быть любым.
@Vitaly
Я делал всё вышеуказанное. Иконка не отображается.
В Qt, в проекте «каталог» Ресурсы.
Ресурсы->images.qrc->/images->images/key.png
В Qt, в mainwindow.cpp строка
QIcon trayImage(«:/images/key.png»);
В Windows, в папке с файлами проекта (там где main.cpp и pro файл), есть папка images.
В ней файл key.png.
Корень ресурсного файла проекта — папка с проектом.
В ней есть папка images. В папке файл key.png.
По моему, путь- » :/images/key.png» путь указан верно.
Иконка key.png используется также для формы (окно приложения).
И в окне формы, она отображается корректно.
Несмотря на это, куда бы я не загружал картинку,
у меня она не выводится при запуске приложения. Выводится пустое место.
Я загружал картинку:
в папку images, относительно корня ресурсного файла.
в папку images\images, относительно корня ресурсного файла.
в папку bin — на каталог выше.
Бесполезно.
ОС Windows 7 ultimate, 32 бит. Официальная, «чистая» (без лишнего по).
Специально использую её только для Qt.
@Иван
Выглядеть в редакторе ресурсов должно вот так.
Загрузил исходники примера из статьи на GitHub: https://github.com/xvitaly/traysample.
Добрый день.
Скажите пожалуйста, а почему иконка в трее отображается в начале панели на месте а точнее на одной из кнопок где у окна закрыть, свернуть и развернуть.
В трее же должно отображается вместе с остальными иконками около часов справа, а иконка весит слева. У меня Ubuntu 14.04
Спасибо.
@Alexey
В Ubuntu Unity своё представление трея, которое по понятным причинам не поддерживает никто. Стандартный трей у них раньше вообще не выводился, но после того, как разработчики поняли, что под их дудку плясать никто не собирается, вернули, хоть и криво.