Qt Loading QSS File

Keywords: Qt Attribute

Sketch

Styles are commonly used in Qt. In order to reduce coupling (separate from logical code), we usually define a QSS file, then write the styles of various components (such as QLable, QLineEdit, QPushButton), and finally use QApplication to load the styles, so that the whole application can share the same style.

New QSS file

First, create a new file with the suffix qss, such as style.qss, and add it to the resource file (qrc).

Tip: Absolute or relative paths can also be used.

Writing QSS

Write your own style code in style.qss file, for example:

QToolTip {
            border: 1px solid rgb(45, 45, 45);
            background: white;
            color: black; }

Loading QSS

To facilitate future calls, you can write a static load style function:

#include <QFile>
#include <QApplication>

class CommonHelper
{
public:
    static void setStyle(const QString &style) {
        QFile qss(style);
        qss.open(QFile::ReadOnly);
        qApp->setStyleSheet(qss.readAll());
        qss.close();
    }
};

Then, load in the main function:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // Loading QSS Style
    CommonHelper::setStyle("style.qss");

    MainWindow window;
    window.show();

    return a.exec();
}

Realization principle

It's easy to find that qApp is a singleton of QCore Application, and then convert it to QApplication.

#if defined(qApp)
#undef qApp
#endif
#define qApp (static_cast<QApplication *>(QCoreApplication::instance()))

So why has all the component styles changed after Q Application calls setStyleSheet()?

Through layer-by-layer analysis, we find that setStyle():

void QApplication::setStyle(QStyle *style)
{
    if (!style || style == QApplicationPrivate::app_style)
        return;

    QWidgetList all = allWidgets();

    // clean up the old style
    if (QApplicationPrivate::app_style) {
        if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
            for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
                QWidget *w = *it;
                if (!(w->windowType() == Qt::Desktop) &&        // except desktop
                     w->testAttribute(Qt::WA_WState_Polished)) { // has been polished
                    QApplicationPrivate::app_style->unpolish(w);
                }
            }
        }
        QApplicationPrivate::app_style->unpolish(qApp);
    }

    QStyle *old = QApplicationPrivate::app_style; // save

    QApplicationPrivate::overrides_native_style =
        nativeStyleClassName() == QByteArray(style->metaObject()->className());

#ifndef QT_NO_STYLE_STYLESHEET
    if (!QApplicationPrivate::styleSheet.isEmpty() && !qobject_cast<QStyleSheetStyle *>(style)) {
        // we have a stylesheet already and a new style is being set
        QStyleSheetStyle *newProxy = new QStyleSheetStyle(style);
        style->setParent(newProxy);
        QApplicationPrivate::app_style = newProxy;
    } else
#endif // QT_NO_STYLE_STYLESHEET
        QApplicationPrivate::app_style = style;
    QApplicationPrivate::app_style->setParent(qApp); // take ownership

    // take care of possible palette requirements of certain gui
    // styles. Do it before polishing the application since the style
    // might call QApplication::setPalette() itself
    if (QApplicationPrivate::set_pal) {
        QApplication::setPalette(*QApplicationPrivate::set_pal);
    } else if (QApplicationPrivate::sys_pal) {
        clearSystemPalette();
        initSystemPalette();
        QApplicationPrivate::initializeWidgetPaletteHash();
        QApplicationPrivate::initializeWidgetFontHash();
        QApplicationPrivate::setPalette_helper(*QApplicationPrivate::sys_pal, /*className=*/0, /*clearWidgetPaletteHash=*/false);
    } else if (!QApplicationPrivate::sys_pal) {
        // Initialize the sys_pal if it hasn't happened yet...
        QApplicationPrivate::setSystemPalette(QApplicationPrivate::app_style->standardPalette());
    }

    // initialize the application with the new style
    QApplicationPrivate::app_style->polish(qApp);

    // re-polish existing widgets if necessary
    if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
        for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
            QWidget *w = *it;
            if (w->windowType() != Qt::Desktop && w->testAttribute(Qt::WA_WState_Polished)) {
                if (w->style() == QApplicationPrivate::app_style)
                    QApplicationPrivate::app_style->polish(w);                // repolish
#ifndef QT_NO_STYLE_STYLESHEET
                else
                    w->setStyleSheet(w->styleSheet()); // touch
#endif
            }
        }

        for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
            QWidget *w = *it;
            if (w->windowType() != Qt::Desktop && !w->testAttribute(Qt::WA_SetStyle)) {
                    QEvent e(QEvent::StyleChange);
                    QApplication::sendEvent(w, &e);
                    w->update();
            }
        }
    }

#ifndef QT_NO_STYLE_STYLESHEET
    if (QStyleSheetStyle *oldProxy = qobject_cast<QStyleSheetStyle *>(old)) {
        oldProxy->deref();
    } else
#endif
    if (old && old->parent() == qApp) {
        delete old;
    }

    if (QApplicationPrivate::focus_widget) {
        QFocusEvent in(QEvent::FocusIn, Qt::OtherFocusReason);
        QApplication::sendEvent(QApplicationPrivate::focus_widget->style(), &in);
        QApplicationPrivate::focus_widget->update();
    }
}

It is divided into four steps:

  1. Clean up the old style - unpolish() Initial
  2. New Style - polish()
  3. Load new styles - polish() + sendEvent(), update()
  4. Delete the old style - delete()

The collection of all controls is obtained by calling QWidgetList all = allWidgets(), and then each control is processed by using the iterator QWidgetList::ConstIterator. Finally, QEvent::StyleChange events are sent through QApplication::sendEvent() to achieve global style changes.

More reference

  • QSS (Grammar Highlighting) of Qt
  • QSS (Style Sheet Grammar) [Transfer]
  • QSS (Dynamic Property) of Qt
  • QSS of Qt (Q_PROPERTY-Primitive Attribute) [Transfer]
  • QSS of Qt (Q_PROPERTY-Custom Property) [Transfer]
  • QSS (QDark Style Sheet) of Qt
  • QSS of Qt
  • QSS (White and Beautiful) of Qt
  • Interface Skin Change of Qt

Posted by wiccan8888 on Fri, 17 May 2019 10:40:49 -0700