简述

Qt中关于样式的使用很常见,为了降低耦合性(与逻辑代码分离),我们通常会定义一个QSS文件,然后编写各种部件(例如:QLable、QLineEdit、QPushButton)的样式,最后使用QApplication进行样式加载,这样,就可以让整个应用程序就共享同一个样式。

新建QSS文件

首先,新建一个后缀名为qss的文件,例如:style.qss,将其加入资源文件(qrc)中。

提示:也可以使用绝对路径或相对路径。

编写QSS

在style.qss文件中编写自己的样式代码,例如:

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

加载QSS

为了方便以后调用,可以写一个静态加载样式的函数:

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

然后,在主函数里进行加载:

int main(int argc, char *argv[])
{
QApplication a(argc, argv); // 加载QSS样式
CommonHelper::setStyle("style.qss"); MainWindow window;
window.show(); return a.exec();
}

实现原理

很容易发现,原来qApp是QCoreApplication的一个单例,然后,将其转换为QApplication。

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

那么,QApplication调用setStyleSheet()以后为何所有的部件样式都改变了呢?

通过逐层分析,我们发现其主要是调用了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();
}
}

主要分为4步:

  1. 清理旧样式 - unpolish()
  2. 初始化新样式 - polish()
  3. 加载新样式 - polish() + sendEvent()、update()
  4. 删除旧样式 - delete

通过调用QWidgetList all = allWidgets()获取了所有控件的集合,然后,利用迭代器QWidgetList::ConstIterator对每一个控件进行处理,最后,通过QApplication::sendEvent()来发送QEvent::StyleChange事件,达到全局样式更改。

更多参考

Qt之加载QSS文件的更多相关文章

  1. QT运行时加载UI文件

      写QT程序里运行时加载UI文件,代码如下: 点击(此处)折叠或打开 #include "keyboard.h" #include <QtUiTools> #incl ...

  2. QUiLoader 动态加载.ui文件

    动态加载UI文件是指,用 Qt Designer 通过拖拽的方式生产.ui 文件.不用 uic工具把.ui 文件变成等价的 c++代码,而是在程序运行过程中需要用到UI文件时,用 QUiLoader ...

  3. 详解QUiLoader 动态加载.ui文件

    http://blog.chinaunix.net/uid-13838881-id-3652523.html 1.适用情况: 动态加载UI文件是指,用 Qt Designer 通过拖拽的方式生产.ui ...

  4. webpack模块加载css文件及图片地址

    webpack支持css文件加载并打包,只需安装相应加载器并在配置文件中配置 . 加载的css文件内容会与该模块里的js内容混合封装,这样做的好处是一个js文件包含了所有的css与js内容,有效减少了 ...

  5. 速战速决 (5) - PHP: 动态地创建属性和方法, 对象的复制, 对象的比较, 加载指定的文件, 自动加载类文件, 命名空间

    [源码下载] 速战速决 (5) - PHP: 动态地创建属性和方法, 对象的复制, 对象的比较, 加载指定的文件, 自动加载类文件, 命名空间 作者:webabcd 介绍速战速决 之 PHP 动态地创 ...

  6. Java提高篇——JVM加载class文件的原理机制

    在面试java工程师的时候,这道题经常被问到,故需特别注意. 1.JVM 简介 JVM 是我们Javaer 的最基本功底了,刚开始学Java 的时候,一般都是从“Hello World ”开始的,然后 ...

  7. assets 加载资源文件

    引用:http://abc20899.iteye.com/blog/1096620 1.获取资源的输入流 资源文件 sample.txt 位于 $PROJECT_HOME/assets/ 目录下,可以 ...

  8. 如何在SCENEKIT使用SWIFT RUNTIME动态加载COLLADA文件

    问题:今天接到一个项目,负责弄需求的美眉跟我讲能不能做一个原型能够加载Collada文件,流程如下: 用户用app下载Collada 压缩包(如内购项目) 压缩包解压 展示Collada文件里的内容 ...

  9. 动态加载js文件

    由于最近在弄echarts,关于地图类的效果,但是全国地图整体的js文件太大了,加载很耗费资源,所以要根据不同省份加载不同地区的js地图, 于是就想的比较简单, var script = docume ...

随机推荐

  1. 【转载】linux内核笔记之高端内存映射

    原文:linux内核笔记之高端内存映射 在32位的系统上,内核使用第3GB~第4GB的线性地址空间,共1GB大小.内核将其中的前896MB与物理内存的0~896MB进行直接映射,即线性映射,将剩余的1 ...

  2. Linux安装配置JDK

    如果想看Windows下的安装,请访问此链接: http://www.cnblogs.com/yoyotl/p/5101321.html 1. 去官网下载Linux版本的jdk安装包,(我下载的是ta ...

  3. 【转】Kali Linux 新手折腾笔记

    原作者:http://defcon.cn/1618.html 最近在折腾Kali Linux 顺便做一简单整理,至于安装就不再多扯了,估计会出现的问题上一篇文章<VMware虚拟机安装Kali ...

  4. CUBRID学习笔记 13 日志文件

    欢迎转载 ,转载时请保留作者信息.本文版权归本人所有,如有任何问题,请与我联系wang2650@sohu.com . 过错 CUBRID Broker Log Files  可以理解为数据库中间件日志 ...

  5. ubuntu下卸载vmware

    直接crl+alt+t打开一个terminal,然后输入sudo vmware-installer --uninstall-product vmware-workstation即可卸载!操作如下图: ...

  6. html bootstrap 表头固定在顶部,表列 可以自由滚动的效果

    该效果主要是依照 bootstrap 的一个样式,class="navbar-fixed-top"; 参考网址为:http://v3.bootcss.com/components/ ...

  7. winscp 软件。

    winscp 软件.是管理服务器的软件. 我们可以输入ip和password,对服务器上的代码进行管理.

  8. iOS - MVP 架构模式

    1.MVP 从字面意思来理解,MVP 即 Modal View Presenter(模型 视图 协调器),MVP 实现了 Cocoa 的 MVC 的愿景.MVP 的协调器 Presenter 并没有对 ...

  9. (转)jQuery轻量级响应式图片轮播插件ResponsiveSlides.js(仅1kb)也可以做纯文本轮播

    ResponsiveSlides.js是一个展示同一容器内图片的轻量级响应式jQuery幻灯片插件(tiny responsive slideshow jQuery plugin).它支持包括IE6在 ...

  10. FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_REORDER_TO_FRONT用法

    Activity的两种启动模式: FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_REORDER_TO_FRONT 1. 如果已经启动了四个Activity:A,B,C和D ...