В данном 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.
Вот это часть кода не очень понятна
QIcon trayImage(":/images/abc.png");Тут указан относительный (если я ошибаюсь) путь к картинке.
Куда бы я не загружал картинку, у меня она не выводится при запуске приложения.
Всё работает, а картинки нет. Меню выводится на «пустом месте».
Скажите пожалуйста — где должна располагаться картинка, в ОС 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 своё представление трея, которое по понятным причинам не поддерживает никто. Стандартный трей у них раньше вообще не выводился, но после того, как разработчики поняли, что под их дудку плясать никто не собирается, вернули, хоть и криво.