В данном 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 своё представление трея, которое по понятным причинам не поддерживает никто. Стандартный трей у них раньше вообще не выводился, но после того, как разработчики поняли, что под их дудку плясать никто не собирается, вернули, хоть и криво.