Evgenii Legotckoi
Evgenii LegotckoiJan. 23, 2016, 9:48 p.m.

Qt/C++ - Lesson 042. PopUp notification in the Gnome style using Qt

Functionality of the standard notification system tray at times can be insufficient for the implementation of ambitious pans for styling applications. We therefore consider the embodiment of pop-up messages in the style of PopUp DE Gnome notification, namely, as shown in the following figure.

PopUp notification Gnome style

To demonstrate the notification I propose to create an application, which will be a field for entering text, and a button by pressing which will be called a pop-up message.

The message will be displayed in the lower right corner of the tray system tray. This notice must be sure to scale the contents.

Fade-in it will be implemented within 150 milliseconds and the disappearance, after three seconds.

Project structure

  • PopupWindow.pro - the profile of the project;
  • mainwindow.h - header file of the main application window;
  • mainwindow.cpp - file source code of the main application window;
  • mainwindow.ui - form the main application window;
  • main.cpp - start file the application source code;
  • popup.h - header file notifications;
  • popup.cpp - file source pop-up message.

PopupWindow.pro и mainwindow.ui

The profile of the project, do not connect anything special, but in the main application window, just put a button and a text entry field.


The header of the main window of the application you must include the header file PopUp notification and declare the notification object itself, and there will be declared a slot for processing pressing the start button a pop-up notification. This slot will be installed in the text notification and position change notifications on the computer screen in the notification size.


#include <QMainWindow>
#include "popup.h"

namespace Ui {
class MainWindow;

class MainWindow : public QMainWindow

    explicit MainWindow(QWidget *parent = 0);

private slots:
    void on_pushButton_clicked();

    Ui::MainWindow *ui;
    PopUp *popUp;       

#endif // MAINWINDOW_H


#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    ui(new Ui::MainWindow)
    popUp = new PopUp();


    delete ui;

void MainWindow::on_pushButton_clicked()



In order to prepare the notification must be inherited from QWidget class that you want to disable window decoration, and put a transparent background. You also need to set it up so that a notice was always on top of all windows. Rendering translucent background notification will be made in the method paintEvent() , in which the full width and height of the notification widget is drawn semi-transparent black rectangle with rounded edges.

Animation appearance and disappearance of the notification will be made through QPropertyAnimation object.

What is important: fitting the size of the widget should be made at the time the text in the notification, and not during the redrawing or installation location notifications on the screen, or to be received is not correct size and magnitude of the notice, it will not in the expected location, or not with the expected size.

To implement time-limited display notifications on the screen applies QTimer .

#ifndef POPUP_H
#define POPUP_H

#include <QWidget>
#include <QLabel>
#include <QGridLayout>
#include <QPropertyAnimation>
#include <QTimer>

class PopUp : public QWidget

    Q_PROPERTY(float popupOpacity READ getPopupOpacity WRITE setPopupOpacity)

    void setPopupOpacity(float opacity);
    float getPopupOpacity() const;

    explicit PopUp(QWidget *parent = 0);

    void paintEvent(QPaintEvent *event);    // The background will be drawn through the redraw method

public slots:
    void setPopupText(const QString& text); // Setting text notification
    void show();                            /* own widget displaying method 
                                             * It is necessary to pre-animation settings
                                             * */

private slots:
    void hideAnimation();                   // Slot start the animation hide
    void hide();                            /* At the end of the animation, it is checked in a given slot,
                                             * Does the widget visible, or to hide
                                             * */

    QLabel label;           
    QGridLayout layout;     
    QPropertyAnimation animation;  
    float popupOpacity;     
    QTimer *timer;          

#endif // POPUP_H


#include "popup.h"
#include <QPainter>
#include <QApplication>
#include <QDesktopWidget>
#include <QDebug>

PopUp::PopUp(QWidget *parent) : QWidget(parent)
    setWindowFlags(Qt::FramelessWindowHint |        // Disable window decoration
                   Qt::Tool |                       // Discard display in a separate window
                   Qt::WindowStaysOnTopHint);       // Set on top of all windows
    setAttribute(Qt::WA_TranslucentBackground);     // Indicates that the background will be transparent
    setAttribute(Qt::WA_ShowWithoutActivating);     // At the show, the widget does not get the focus automatically

    animation.setTargetObject(this);                // Set the target animation
    animation.setPropertyName("popupOpacity");      // 
    connect(&animation, &QAbstractAnimation::finished, this, &PopUp::hide); 

    label.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); 
    label.setStyleSheet("QLabel { color : white; "
                        "margin-top: 6px;"
                        "margin-bottom: 6px;"
                        "margin-left: 10px;"
                        "margin-right: 10px; }");

    layout.addWidget(&label, 0, 0);

    timer = new QTimer();
    connect(timer, &QTimer::timeout, this, &PopUp::hideAnimation);

void PopUp::paintEvent(QPaintEvent *event)

    QPainter painter(this);

    QRect roundedRect;
    roundedRect.setX(rect().x() + 5);
    roundedRect.setY(rect().y() + 5);
    roundedRect.setWidth(rect().width() - 10);
    roundedRect.setHeight(rect().height() - 10);


    painter.drawRoundedRect(roundedRect, 10, 10);

void PopUp::setPopupText(const QString &text)
    label.setText(text);    // Set the text in the Label
    adjustSize();           // With the recalculation notice sizes

void PopUp::show()
    setWindowOpacity(0.0);  // Set the transparency to zero

    animation.setDuration(150);     // Configuring the duration of the animation
    animation.setStartValue(0.0);   // The start value is 0 (fully transparent widget)
    animation.setEndValue(1.0);     // End - completely opaque widget

    setGeometry(QApplication::desktop()->availableGeometry().width() - 36 - width() + QApplication::desktop() -> availableGeometry().x(),
                QApplication::desktop()->availableGeometry().height() - 36 - height() + QApplication::desktop() -> availableGeometry().y(),


void PopUp::hideAnimation()

void PopUp::hide()
    // If the widget is transparent, then hide it
    if(getPopupOpacity() == 0.0){

void PopUp::setPopupOpacity(float opacity)
    popupOpacity = opacity;


float PopUp::getPopupOpacity() const
    return popupOpacity;


Archive of the source: PopupWindow

As a result, the message will be as follows:


We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

  • June 14, 2018, 8:40 p.m.

В Astra Linux вместо прозрачности черный фон. Не знаеете, что может быть?

Evgenii Legotckoi
  • June 18, 2018, 1:10 p.m.

Недоработки, вряд ли этот зверь вообще является официально поддерживаемым

  • July 11, 2019, 10:27 p.m.

Евгений, не совсем понимаю, как связывается свойство полупрозрачности Q_PROPERTY(float popupOpacity READ getPopupOpacity WRITE setPopupOpacity) со свойством анимации QPropertyAnimation animation. Проясните момент. И где про это прочитать поподробнее.

Evgenii Legotckoi
  • July 12, 2019, 2:24 a.m.

Все свойства в объектах, которые наследуются от Q_OBJECT и помечены макросом Q_PROPERTY, могут вызываться по своему имени с помощью QMetaObject::invokeMethod . Подробнее можете почитать в документации на QMetaObject .

Именно это и используется для вызова свойста внутри QPropertyAnimation. Исходники я не смотрел, но уверен но 100% что там будет QMetaObject::invokeMethod или что-то похожее.

Обычно используется так

QString retVal;
QMetaObject::invokeMethod(obj, "compute", Qt::DirectConnection,
                          Q_RETURN_ARG(QString, retVal),
                          Q_ARG(QString, "sqrt"),
                          Q_ARG(int, 42),
                          Q_ARG(double, 9.7));

А о том, какое свойство вызывать QPropertyAnimation узнаёт через установку целевого объекта и имени свойства объекта, которое нужно вызывать.

animation.setTargetObject(this);                // Устанавливаем целевой объект анимации
animation.setPropertyName("popupOpacity");      // Устанавливаем анимируемое свойство

Видимо это был такой способ обойти шаблонизацию в своё время у них. Думаю, что сейчас это можно с помощью шаблонов решать более изящно. Но вообще, очень не удобно, когда в проекте повсеместно используют QMetaObject::invokeMethod . Трудно отлаживать и иногда вообще не ясно откуда прилетает вызов функции, а callstack так вообще уродский.

  • June 20, 2020, 7:15 p.m.
  • (edited)

Переписал на python, но почему-то не закрывается при вызове hide()? А при вызове из другого модуля вообще не отображается окно?

# This Python file uses the following encoding: utf-8
import sys
import os

from PySide2.QtWidgets import QWidget, QLabel, QGridLayout, QApplication 
from PySide2.QtCore import QTimer, QPropertyAnimation, Qt, QRect
from PySide2.QtGui import QPainter, QBrush, QColor, QBackingStore

class Info(QWidget):
    def __init__(self, text = "", parent = None):

        self.text = text
        self.label = QLabel(text)                        # Label с сообщением
        self.layout = QGridLayout()                  # Размещение для лейбла
        self.animation = QPropertyAnimation(self)    # Свойство анимации для всплывающего сообщения
                         # Свойства полупрозрачности виджета
        self.timer = QTimer()                        # Таймер, по которому виджет будет скрыт

        self.setWindowFlags(Qt.FramelessWindowHint |       # Отключаем оформление окна
                   Qt.Tool |                               # Отменяем показ в качестве отдельного окна
                   Qt.WindowStaysOnTopHint)                # Устанавливаем поверх всех окон
        self.setAttribute(Qt.WA_TranslucentBackground)     # Указываем, что фон будет прозрачным
        self.setAttribute(Qt.WA_ShowWithoutActivating)     # При показе, виджет не получается фокуса автоматически

        self.animation.setTargetObject(self)                 # Устанавливаем целевой объект анимации
        self.animation.setPropertyName(b'windowOpacity')       # Устанавливаем анимируемое свойство

        #self.animation.stateChanged.connect(self.hide())        # Подключаем сигнал окончания анимации к слоты скрытия     
        #connect(&animation, &QAbstractAnimation::finished, this, &PopUp::hide); 

        # Настройка текста уведомления
        self.label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # Устанавливаем по центру
        # И настраиваем стили
        self.label.setStyleSheet("QLabel { color : white; "
                            "margin-top: 6px;"
                            "margin-bottom: 6px;"
                            "margin-left: 10px;"
                            "margin-right: 10px; }")

        # Производим установку текста в размещение, ...
        self.layout.addWidget(self.label, 0, 0)
        self.setLayout(self.layout)  # которое помещаем в виджет

        # По сигналу таймера будет произведено скрытие уведомления, если оно видимо
        #self.timer = QTimer()

        #connect(timer, &QTimer::timeout, this, &PopUp::hideAnimation);

    #def popupOpacity(self):   
    #   return self._popupOpacity

    #def popupOpacity(self, opacity):
    #   self._popupOpacity = opacity
    #   self.setWindowOpacity(opacity)

    def paintEvent(self, event):
        painter = QPainter(self)        
        painter.setRenderHint(QPainter.Antialiasing)    # Включаем сглаживание

        # Подготавливаем фон. rect() возвращает внутреннюю геометрию виджета уведомления, по содержимому
        roundedRect = QRect()
        roundedRect.setX(self.rect().x() + 5)
        roundedRect.setY(self.rect().y() + 5)
        roundedRect.setWidth(self.rect().width() - 10)
        roundedRect.setHeight(self.rect().height() - 10)

        # Кисть настраиваем на чёрный цвет в режиме полупрозрачности 180 из 255
        painter.setPen(Qt.NoPen)     # Край уведомления не будет выделен

        # Отрисовываем фон с закруглением краёв в 10px
        painter.drawRoundedRect(roundedRect, 10, 10)

    def setPopupText(self, text):
        self.label.setText(text)       # Устанавливаем текст в Label
        self.adjustSize()          # С пересчётом размеров уведомления

    def show(self):
        self.setWindowOpacity(0.0)          # Устанавливаем прозрачность в ноль

        self.animation.setDuration(150)     # Настраиваем длительность анимации
        self.animation.setStartValue(0.0)   # Стартовое значение будет 0 (полностью прозрачный виджет)
        self.animation.setEndValue(1.0)     # Конечное - полностью непрозрачный виджет

        self.setGeometry(QApplication.desktop().availableGeometry().width() - 36 - self.width() + QApplication.desktop().availableGeometry().x(),
                    QApplication.desktop().availableGeometry().height() - 36 - self.height() + QApplication.desktop().availableGeometry().y(),

        QWidget.show(self)              # Отображаем виджет, который полностью прозрачен

        self.animation.start()      # И запускаем анимацию
        self.timer.start(3000)      # А также стартуем таймер, который запустит скрытие уведомления через 3 секунды

    def hideAnimation(self):
        self.timer.stop()                   # Останавливаем таймер
        self.animation.setDuration(100)     # Настраиваем длительность анимации
        self.animation.setStartValue(1.0)   # Стартовое значение будет 1 (полностью непрозрачный виджет)
        self.animation.setEndValue(0.0)     # Конечное - полностью прозрачный виджет
        self.animation.start()              # И запускаем анимацию

    def hide(self):
        # Если виджет прозрачный, то скрываем его

    def __repr__(self):
        return 'Info class'

if __name__ == "__main__":
    # app disexec теперь на pyqt
    app = QApplication(sys.argv)

    window = Info("This works fine")


  • Aug. 6, 2021, 10:22 p.m.

Доброго времени суток.
Возник вопрос - установлена Qt 6.1.2


#include <QDesktopWidget>

Выводит ошибку: popup.cpp:5:10: error: 'QDesktopWidget' file not found

... в Qt 5.15 использовал метод QApplication::desktop()

    setGeometry(QApplication::desktop()->geometry().width() - 36 - width() + QApplication::desktop()->geometry().x(),
                QApplication::desktop()->geometry().height() - 56 - height() + QApplication::desktop()->geometry().y(),

На данный момент ошибка: popup.cpp:81:31: error: no member named 'desktop' in 'QApplication'

В документации - метод QApplication::desktop() устарел - никак не могу понять какой метод использовать ?

Evgenii Legotckoi
  • Oct. 11, 2021, 11:50 a.m.

QApplication имеет метод screens() , который возвращает список экранов. А класс QScreen имеет методы geometry() и availableGeometry() . Можете попробовать через них добиться нужного результата.

  • March 26, 2023, 7:04 p.m.

Включите прозрачность в композит менеджере fly-admin-theme : fly-admin-theme ->Эффекты и всё заработает.

  • March 26, 2023, 7:10 p.m.
  • (edited)

Добрый день, взял за основу ваш PopUp notification , и немного доработал его под свои нужды.
Добавил в отдельном eventloop'e всплывающую очередь уведомлений с анимацией и таймером удаления.
С вашего позволения оставляю здесь ссылку на git


Only authorized users can post comments.
Please, Log in or Sign up

C++ - Test 001. The first program and data types

  • Result:53points,
  • Rating points-4

C++ - Тест 003. Условия и циклы

  • Result:57points,
  • Rating points-2

C++ - Test 005. Structures and Classes

  • Result:100points,
  • Rating points10
Last comments
JonnyJoMay 25, 2023, 2:24 p.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Евгений, благодарю!
Evgenii Legotckoi
Evgenii LegotckoiMay 25, 2023, 4:49 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Код на строчка 184-198 вызывает перерисовку области на каждый 4-й такт счётчика. По той логике не нужно перерисовывать объект постоянно, достаточно реже, чем выполняется игровой слот. А слот вып…
JonnyJoMay 21, 2023, 10:49 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Евгений, благодарю! Всё равно не совсем понимаю :( Если муха двигает ножками только при нажатии клавиш перемещение, то что, собственно, делает код со строк 184-198 в triangle.cpp? В этих строчка…
Evgenii Legotckoi
Evgenii LegotckoiMay 21, 2023, 5:57 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Добрый день. slotGameTimer срабатывает по таймеру и при каждой сработке countForSteps увеличивается на 1, это не зависит от нажатия клавиш, нажатая клавиша лишь определяет положение ножек, котор…
JonnyJoMay 20, 2023, 11:27 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Евгений, здравствуйте! Подскажите, а почему при нажатии одной клавиши переменная countForSteps увеличивается не на 1, на 4, ведь одно действие даёт увеличение этой переменной только на единицу? …
Now discuss on the forum
Evgenii Legotckoi
Evgenii LegotckoiApril 16, 2023, 4:07 a.m.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Да, это возможно. Но подобные вещи лучше запускать через celery. То есть drf принимает команду, и после этого регистрирует задачу в celery, котроый уже асинхронно всё это выполняет. В противном …
Алексей БобровDec. 14, 2021, 7:03 p.m.
Sorting the added QML elements in the ListModel I am writing an alarm clock in QML, I am required to sort the alarms in ascending order (depending on the date or time (if there are several alarms on the same day). I've done the sorting …
Evgenii Legotckoi
Evgenii LegotckoiMarch 29, 2023, 4:11 a.m.
Замена поля ManyToMany Картинки точно нужно хранить в медиа директории на сервере, а для обращения использовать ImageField. Который будет хранить только путь к изображению на сервере. Хранить изображения в базе данных…
Evgenii Legotckoi
Evgenii LegotckoiApril 24, 2023, 3:22 a.m.
Пакеты данных между сервером и клиентами Привет. Если классы имеют что-то общее в полях, а также общую идеологию и их можно вписать в иерархию наследования, то в первую очередь переписать так, чтобы один базовый класс объединял в…

Follow us in social networks