Evgenii Legotckoi
Evgenii LegotckoiТам. 12, 2015, 12:27 Т.Қ.

Qt/C++ - Сабақ 002. QSystemTrayIcon немесе науаға қолданбаны қалай азайтуға болады?

[PyQt5/Python] туралы ұқсас мақала(https://evileg.com/en/post/68/)

Бүгін біз QSystemTrayIcon сыныбы арқылы Qt шеңберінде жазылған қолданбаны операциялық жүйенің науасына қалай азайтуға болатынын талқылаймыз. Бұл функция фондық режимде ұзақ уақыт жұмыс істеуі керек қолданбалар үшін өте пайдалы. Мысалы, бейне жазу немесе дыбысты ойнату қолданбасы.

Ендеше келесі сұрақтарды қарастырайық:

  • Бағдарламаны науаға азайтуға қалай үйрету керек;
  • Қолданбаңыздың науа белгішесі үшін контекстік мәзірді қалай жасауға болады;
  • Қажет болмаса, бұл мүмкіндікті қалай өшіруге болады.

Код Qt 5.4.1 негізінде QtCreator 3.3.1-де жазылған.


QSystemTrayIcon үшін жоба құрылымы

Жоба әдепкі бойынша файлдарды жасайтын Qt Widgets қолданбасы ретінде жасалған:

  • Tray.pro - профиль;
  • mainwindow.h – қосымшаның негізгі терезесінің тақырып файлы;
  • mainwindow.cpp – терезенің бастапқы коды;
  • main.cpp – қолданба басталатын негізгі бастапқы файл;
  • mainwindow.ui – қолданбаның негізгі терезесінің формасы.

Ескерту. Мен негізгі кодтың логикасын қажетсіз ақпаратпен шатастырмау үшін дизайнерде интерфейстің көп бөлігін жасаймын. Шындығында, бұл тек дәм мен әдетке байланысты мәселе .

mainwindow.ui

Науаны тексеруге арналған терезе пішіні Сынақ үшін құсбелгісі бар қарапайым және ерекше пішінді жасайық.

QCheckBox нысанының атауы trayCheckBox

Tray.pro

Бұл файл әдепкі параметрлермен қалды.

#-------------------------------------------------
#
# 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

Бұл файл да өзгертілмеген.

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

Тақырып файлы қазірдің өзінде өзгертілуде, өйткені бізге терезені жабу оқиғасын қадағалау керек, сонымен қатар қолданба науасы белгішесі үшін басу өңдеушісін жасау керек. Сондай-ақ осы файлға барлық қажетті кітапханаларды қосуды ұмытпаңыз. Әйтпесе, жоба құрастырылмайды.

#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

Тексерілетін қолданбаның барлық логикасы осы сыныпта қамтылған. Құсбелгі қойылған жағдайда ғана қолданба науаға кішірейтіледі. Құсбелгінің орнына айнымалы немесе осы функцияның жұмыс істеу қажеттілігі туралы ақпаратты сақтаудың кез келген басқа жолы болуы мүмкін.

контекстік мәзірі бар қолданба науасы белгішесі Бұл жағдайда құсбелгі қойылған кезде қолданбадан шығу үшін контекстік мәзірдегі сәйкес элемент пайдаланылады.

Сондай-ақ, қолданба науаға кішірейткен кезде, пайдаланушыны осы оқиға туралы хабардар ететін сәйкес хабарлама пайда болады.

#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;
    }
}

Барлығы

Жоба сәтті құрастырылған жағдайда, қолданбаңыз науаға оңай оралады. Қолданбаның QSystemTrayIcon көмегімен жұмыс істеу мысалы келесі бейнеде көрсетілген:

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

BlinCT
  • Сәуір 16, 2016, 4:14 Т.Қ.
Вопрос такой, на сколько большая разница в реализации трея на Qt или на QML как у вас есть еще такое видео?
И то и другое можно применить для десктопного приложения, и как лучше строить выбор?
Evgenii Legotckoi
  • Сәуір 16, 2016, 11:40 Т.Қ.
В QML нет собственного типа для системного трея. Поэтому нужно регистрировать через qmlRegisterType сам QSystemTrayIcon, либо класс, в который обёрнут QSystemTrayIcon.
Два примера реализации системного трея с использованием QML есть вот в этом уроке: http://www.evileg.ru/baza-znanij/qt-qml-android/rabota-s-system-tray-v-qml-qt-prilozhenii.html
СС
  • Ақп. 21, 2017, түнжарым

Добрый день.
При попытке запуска приложения в Qt Creator 4.2.0 на Qt 5.7.1 выдаёт следующие ошибки (как при ручном вводе кода, так и при копировании с сайта):



1. В файле mainwindow.cpp :

E:\Proj\Qt\Tray\mainwindow.cpp:21: ошибка: invalid use of incomplete type 'class QMenu'
QMenu *menu = new QMenu(this);
^


Помогло добавление директивы в заголовок данного файла, либо (что как мне кажется более грамотно) в mainwindow.h :

#include <QMenu>


Спасибо за урок!
Evgenii Legotckoi
  • Ақп. 21, 2017, 12:16 Т.Ж.

Видимо, когда я работал с этим кодом, QMenu подключался в заголовочнике QSystemTrayIcon , поэтому и сработало нормально. В любом случае ваше решение верное. Внесу поправку, что если у Вас нет объявлений QMenu в заголовочнике, то лучше перенеси include в cpp файл.

СС
  • Ақп. 22, 2017, 12:41 Т.Ж.

Спасибо! А чем ваш вариант лучше? Скажу сразу, что не совсем хорошо разбираюсь в C++ (школьная программа была пройдена, - в институте немного "подзабил")), но вроде при инклюде заголовочного файла с объявленным QMenu, например в другой .cpp, в нём тоже всё будет работать, иначе для каждого cpp-файла QMenu будет подключаться отдельно - выходит, это более оптимально?

Evgenii Legotckoi
  • Ақп. 22, 2017, 1:38 Т.Ж.

Это к вопросу о скорости компиляции проекта. В маленьких проектах это не очень заметно, а в крупных становится очевидным.

Если всё подключать в заголовочниках, то много времени тратится на проверку того, был ли уже тот или иной заголовочник подключён в в конкретном заголовочном файле. А если стараться подключать заголовочные файлы в файле исходных кодов, то количество таких проверок снижается, соответственно уменьшается время на сборку проекта.

Также есть ещё один хороший способ увеличить скорость компиляции, если объект какого-либо класса, например того же самого QMenu объявляется как указатель в заголовочном файле, то можно объявить класс QMenu, а заголовочный файл подключить уже в файле исходных кодов.

Это будет выглядеть следующим образом:

widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class QMenu;

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
    QMenu *menu;
};

#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"

#include <QMenu>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    menu = new QMenu(this);
}
ДЧ
  • Маусым 9, 2017, 9:07 Т.Ж.

У кого при компиляции ворненги - отредактируйте код таким образом, чтобы trUtf8() не было, а было просто tr()

x
  • Сәуір 18, 2018, 8:36 Т.Ж.

Здравствуйте, извиняюсь за вопрос немного не по теме урока, а скорее по общему синтаксису Qt, связанному с активным использованием указателей.
В частности в вашем примере, разве new QMenu, QAction и QSystemTrayIconnew без их последующего delete не должно приводить к утечке памяти?

Evgenii Legotckoi
  • Сәуір 18, 2018, 10:24 Т.Ж.

Добрый день!

В рамках самого Qt здесь утечки не будет. Особенность фреймворка в том, что при создании объектов, которыe наследованы от QObject (подавляющее большинство классов), передаётся указатель на parent объект, как в случае с меню
new QMenu(this); // this - указатель на parent объект
Когда parent-объект будет удалён, он прихватит за собой и все объекты, которые получили указатель на parent`a. То есть автоматически подчистит память.
Если не передать указатель на парента, то утечка конечно будет. Передача указателя на парента является опциональной, можете и не передавать, если этого требует архитектура приложения, но тогда нужно будет следить за утечками.

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз