Qt加载.css/.qss文件设置控件的QSS样式(支持程序运行时修改且立即生效类似换肤效果)

初学Qt时,你是如何设置QWidget,QPushButton等原生基础控件的样式的?是不是主要是两种方法?

1.直接在可视化的.ui文件中直接添加qss语句。

2.在代码中通过setStyleSheet(QString qss)来设置qss语句。

上述两种方法,在程序规模很大时,很多地方需要复用样式会非常麻烦,qss语句写的到处都是,极难维护,要你改一个按钮样式你都要到处翻,还要一个个改,烦到想死!

于是,

为了更好地管理样式,提高复用率,应该把QSS样式语句写在一个个文件中(文件后缀是.css或者.qss都可以,但是建议保存为.css文件好点,因为Notepad++可以进行语法识别高亮提醒,另外样式相关的文件编码最好是UTF-8带BOM),程序初始化时统一加载到主程序中,这样所有控件都会自动继承,且通过属性过滤器决定哪个控件生效(如下图)。

我喜欢根据Qt原生支持QSS语句改变样式的基础控件都单独一个.css文件,例如QPushButton.css、QWidget.css、QLabel.css等。。。你也可以根据你自己程序的每个窗口一个.css文件,随你喜欢,我只是给你一种加载样式的思路。

.css文件在Notepad++中能被传统的CSS的语法识别,获得传统CSS语法的高亮染色显示/自动补全提示等的支持,但是.qss文件是不行的和.txt文本没有区别:

建议使用动态属性标记样式,这样通过设置动态属性就可以复用该样式:

每个控件都可以设置多个动态属性,意味着可以叠加生效多个被动态属性标记的样式:

样式根文件StyleList.txt(文件名随意改)负责记录这些所有的.css文件名

这样通过读取样式根文件“StyleList.txt” 即可知有多少个.css/.qss样式文件可以加载,然后对这些样式文件一个个读取,然后将所有内容拼接成一个超长的QString,再使用setStyleSheet(QString qss)来设置加载到主程序中。期间也可以选择性使用QFileSystemWatcher来监控这些样式文件的内容变化,一旦有内容更新会发出信号,然后马上重新加载所有样式。

举例,我一个测试程序的exe文件在bin目录下,bin同级目录下有res/QSS来存放QSS样式相关文件

创建一个加载qss样式的工具类 “QssLoadTool” 用于加载,并监控这些文件的变化:

qssloadtool.h

#ifndef QSSLOADTOOL_H
#define QSSLOADTOOL_H#include <QObject>
#include <QFile>
#include <QFileSystemWatcher>class QssLoadTool : public QObject
{Q_OBJECT
public:explicit QssLoadTool(QObject *parent = nullptr);// 设置qss样式文件的根文件(根文件记录了需要加载的所有qss样式文件名)static void setQssFileListRootFile(const QString &QssRootFile);static QString getQssFileListRootFile();// 加载所有qss文件刷新程序控件样式static void LoadQss2RefreshStyle();// 监控qss相关文件,发送修改就重新加载(在main调用一次即可)static void WatchQSSFileChange(QFileSystemWatcher *FileWatcher);private :// 本程序所需qss样式文件的根文件static QString m_QssRootFile;// 程序运行位置static QString m_currentPath;
};#endif // QSSLOADTOOL_H

qssloadtool.cpp

#include "qssloadtool.h"
#include <QDebug>
#include <QApplication>QString QssLoadTool::m_QssRootFile = "";QssLoadTool::QssLoadTool(QObject *parent) : QObject(parent)
{// 获取应用程序当前路径m_currentPath = QCoreApplication::applicationDirPath();
}void QssLoadTool::setQssFileListRootFile(const QString &QssRootFile)
{m_QssRootFile = QssRootFile;
}QString QssLoadTool::getQssFileListRootFile()
{return m_QssRootFile;
}void QssLoadTool::LoadQss2RefreshStyle()
{if(m_QssRootFile.isEmpty()){qDebug() << "未设置qss样式文件的根文件:" << m_QssRootFile;return;}qDebug() << __FUNCTION__ << "qss样式发送变更,正在重新加载...";QFile file(m_QssRootFile);if (file.open(QIODevice::ReadOnly)){QString style = file.readAll();file.close();QStringList styleList = style.split("\n");style.clear();QString path = "";for(const QString &qssfile : styleList){path = m_currentPath + "/../res/QSS/" + qssfile;file.setFileName(path.trimmed());if(file.open(QIODevice::ReadOnly)){style = style + file.readAll().trimmed();file.close();}else{qDebug() << "打开文件失败! ---> " << path;}}qobject_cast<QApplication*>(QApplication::instance())->setStyleSheet(style);}
}void QssLoadTool::WatchQSSFileChange(QFileSystemWatcher *FileWatcher)
{if(m_QssRootFile.isEmpty()){qDebug() << "未设置qss样式文件的根文件:" << m_QssRootFile;return;}FileWatcher->addPath(m_QssRootFile);qDebug() << "监控qss样式文件的根文件:" << m_QssRootFile;QFile file(m_QssRootFile);if (file.open(QIODevice::ReadOnly)){QString files = file.readAll();file.close();QStringList fileList = files.split("\n");QString path = "";for(const QString &qssfile : fileList){path = m_currentPath + "/../res/QSS/" + qssfile;FileWatcher->addPath(path.trimmed());qDebug() <<"监控qss样式文件 :" << path.trimmed();}}// 被监控的qss文件发生修改时,马上重新加载所有qss样式文件QObject::connect(FileWatcher, &QFileSystemWatcher::fileChanged, [](){QssLoadTool::LoadQss2RefreshStyle();});
}

main.cpp中使用方式:

int main(int argc, char *argv[])
{QApplication a(argc, argv);// 获取exe所在位置(用于拼接样式根文件的相对路径)QString currentPath = QCoreApplication::applicationDirPath();// 设置样式根文件QssLoadTool::setQssFileListRootFile(currentPath + "/../res/QSS/StyleList.txt");// 通过上一步设置的样式根文件去加载每一个.css样式文件QssLoadTool::LoadQss2RefreshStyle(); // 监控所有样式文件的内容变化,一旦发生变化就马上刷新样式并生效// (如果不想监控,那就接下来的这两句代码不写)QFileSystemWatcher fileWatcher;QssLoadTool::WatchQSSFileChange(&fileWatcher);// 主界面启动ProjectMainWindow w;w.show();return a.exec();
}

注意:程序运行中,换肤操作后,控件的样式不生效时,说明需要显式调用样式初始化函数手动重新初始化,在合适的地方调用以下方法重新初始化控件样式。

void QStyle::polish(QWidget *widget)

void QStyle::polish(QApplication *application)

void QStyle::polish(QPalette &palette)

另外还可以取消控件的样式:

void QStyle::unpolish(QWidget *widget)

void QStyle::unpolish(QApplication *application)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/593628.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序短链接工具推荐

现在微信小程序大行其道&#xff0c;但工作中大部分人选择了短链接的方式来推广微信小程序&#xff0c;那么微信小程序短链接工具哪个好?今天就分享一篇从网上看到的关于《微信小程序短链接工具推荐》文&#xff0c;作者是souki&#xff0c;一起来看看吧! 一、缩链 1、生成方…

虚幻UE5对接物联网教程

一、背景 这几年&#xff0c;智慧城市/智慧交通/智慧水利等飞速发展&#xff0c;骑士特意为大家做了一个这块的学习路线。 二、这是学习大纲 1.给虚幻UE5初学者准备的智慧城市/数字孪生蓝图开发教程 https://www.bilibili.com/video/BV1894y1u78G 2.UE5数字孪生蓝图开发教学…

基于架构的软件开发方法_1.概述和相关概念及术语

1.体系结构的设计方法概述 基于体系结构的软件设计&#xff08;Architecture-Based Software Design&#xff0c;ABSD&#xff09;方法。ABSD方法是由体系结构驱动的&#xff0c;即指由构成体系结构的商业、质量和功能需求的组合驱动的。 使用ABSD方法&#xff0c;设计活动可以…

Vue项目中引入html页面(vue.js中引入echarts数据大屏html [静态非数据传递!] )

在项目原有vue&#xff08;例如首页&#xff09;基础上引入html页面 1、存放位置 vue3原有public文件夹下 我这边是新建一个static文件夹 专门存放要用到的html文件 复制拖拽过来 index为html的首页 2、更改路径引入到vue中 这里用到的是 iframe 方法 不同于vue的 component…

WebAuthn:更好地保护线上敏感信息

1. 引言 2023年知乎博客 WebAuthn: 真正的无密码身份认证 总结得很赞。 在数字时代&#xff0c;密码已成为人们日常生活和在线活动中不可或缺的一部分。尽管互联网已经发展了 20 多年&#xff0c;许多方面都有了巨大的改进&#xff0c;但只有密码&#xff0c;还是 20 年前的用…

银行业架构网络BIAN (Banking IndustryArchitecture Network)详细介绍

BIAN ( The Banking Industry Architecture Network) 是一个业界多方协作的非营利性组织&#xff0c;由全球领先银行、技术提供商、顾问和学者组成&#xff0c;定义了一个用以简化和标准化核心银行体系结构的银行技术框架。这一框架基于面向服务的架构 (SOA) 原则&#xff0c;银…

java线程的几种状态

目录 正文&#xff1a; 1.JConsole 2.新建状态(New) 3.运行状态(Runnable) 4.阻塞状态(Blocked) 5.等待状态(Waiting) 6.计时等待状态(Timed Waiting) 7.终止状态(Terminated) 总结&#xff1a; 正文&#xff1a; 1.JConsole JConsole是Java监控和管理控制台工具&…

【深度优先】【树上倍增 】2846. 边权重均等查询

本文涉及知识点 深度优先 树上倍增 LeetCode2846. 边权重均等查询 现有一棵由 n 个节点组成的无向树&#xff0c;节点按从 0 到 n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges &#xff0c;其中 edges[i] [ui, vi, wi] 表示树中存在一条位于节点 ui…

【JavaScript 漫游】【053】Reflect

文章简介 本篇文章为【JavaScript 漫游】专栏的第 053 篇文章&#xff0c;记录了 ES6 规范中关于 Reflect 的知识点。 概述 Reflect 对象与 Proxy 对象一样&#xff0c;也是 ES6 为了操作对象而提供的新 API。Reflect 对象的设计目的有这样几个。 &#xff08;1&#xff09…

设计模式 --5观察者模式

观察者模式 观察者模式的优缺点 优点 当一个对象改变的时候 需要同时改变其他对象的相关动作的时候 &#xff0c;而且它不知道有多少具体的对象需要改变 应该考虑使用观察者模式 。观察者模式的工作就是解除耦合 让耦合双方都依赖与抽象 而不是具体 是的各自改变都不会影响另…

聚类算法的先验基础知识

聚类算法的先验基础知识 1. 瑞利商2. 谱定理3. 联合概率4. 条件概率分布5. 边缘分布6. 贝叶斯定理7. 有向图8. 拉格朗日乘子定理 下一篇将介绍整理各种聚类算法&#xff0c;包括k-means&#xff0c;GMM(Guassian Mixture Models, 高斯混合)&#xff0c;EM(Expectation Maximiza…

Java设计模式:外观模式之优雅门面(九)

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 在软件工程中&#xff0c;设计模式是解决常见设计问题的经验总结&#xff0c;它为开发者提供了一种通用的、可复用的解决方案。外…