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:
- Clean up the old style - unpolish() Initial
- New Style - polish()
- Load new styles - polish() + sendEvent(), update()
- 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