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

news2024/11/28 12:50:19

初学Qt时要想通过QSS修改控件QWidget,QPushButton等原生基础控件的样式,一般都是直接在.ui文件中直接添加qss,或者在代码中通过setStyleSheet(QString qss)来设置。当程序很大时,很多地方需要复用样式时会非常麻烦,qss写的到处都是,极难维护(如下图所示两种常见初学方式)。

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

这样通过读取样式根文件“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();
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CCIE-12-IPSec-VPN-RemoteAccess

目录 实验条件网络拓朴实验目的 开始配置1. R2 Ping R3确定基础网络是通的2. 配置R23. 配置R53. 验证 实验条件 网络拓朴 实验目的 为R2和R3建立IPSec VPN R4可以ping通R5 开始配置 R2&#xff1a;模拟需要远程访问网络的网关 R4&#xff1a;模拟需要远程访问网络内的目标主…

问题2-前端json数组数据转换成csv文件

代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>将 JSON 数据导出为 CSV 文件</title> …

node.js的模块化 与 CommonJS规范

一、node.js的模块化 (1)什么是模块化&#xff1f; 将一个复杂的程序文件依据一定的规则拆分成为多个文件的过程就是模块化 在node.js中&#xff0c;模块化是指把一个大文件拆分成独立并且相互依赖的多个小模块&#xff0c;将每个js文件被认为单独的一个模块&#xff1b;模块…

【蓝桥杯】积木

积木 题目描述 小明用积木搭了一个城堡。 为了方便&#xff0c;小明在搭的时候用的是一样大小的正方体积本&#xff0c;搭在了一个 n 行 m 列的方格图上&#xff0c;每个积木正好占据方格图的一个小方格。 当然&#xff0c;小明的城堡并不是平面的&#xff0c;而是立体的。…

mac如何检测移动硬盘 mac硬盘检测工具 Tuxera怎么用 Tuxera NTFS官网

在工作学习中&#xff0c;我们都绕不开用移动硬盘来拷贝存储一些文件。但是在使用过程中&#xff0c;我们经常遇到“mac检测不到移动硬盘”“移动硬盘不存在”等问题&#xff0c;今天本文就带大家了解下mac如何检测移动硬盘&#xff0c;mac硬盘检测工具。 一、mac如何检测移动…

C++ —— C++11新增语法

目录 一&#xff0c;列表初始化 1.1 这是什么&#xff1f; 1.2 initializer_list 1.3 在容器的运用 1.4 STL中的变化 二&#xff0c;右值引用和左值引用 2.1 是什么&#xff1f; 2.2 这两个东西有啥关系&#xff1f; 2.3 有啥用&#xff1f; 三&#xff0c;*移动构…

智乃想考一道鸽巢原理

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e9, maxm 4e4 5; co…

【御控物联】JavaScript JSON结构转换(14):对象To数组——规则属性重组

文章目录 一、JSON结构转换是什么&#xff1f;二、术语解释三、案例之《JSON对象 To JSON数组》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0…

实验:基于Red Hat Enterprise Linux系统的创建磁盘和磁盘分区(一)

目录 一. 实验目的 二. 实验内容 三. 实验设计描述及实验结果 fdisk [参数] [设备] 1. 为虚拟机添加1块大小为3-5G的硬盘nvme&#xff0c;将该硬盘划分1个主分区和两个逻辑分区分别为600MB。 partprobe [选项] [设备] 2. 将主分区格式化为ext4文件系统并挂载到/自己名字命名…

【Go】十五、接口、多态、断言

文章目录 1、接口的引入2、接口3、接口的注意点4、多态5、断言6、Type Switch 1、接口的引入 以日常生活中打招呼为例&#xff0c;定义接口规范&#xff0c;各国人为打招呼为具体的实现 package main import "fmt"//接口的定义&#xff1a;定义规则、定义规范&…

3. WiFi基本原理

1. WiFi简介 WiFi的全称是Wireless Fidelity。它是一种无线网络通信技术&#xff0c;由Wi-Fi联盟拥有&#xff0c;目的是改善基于IEEE 802.11标准的无线网络产品之间的互通性&#xff0c;允许电子设备在没有物理连接的情况下进行高速数据传输。此外&#xff0c;WiFi也被视为IE…

手搓Docker-Image-Creator(DIC)工具(03):实现alpine+jre的镜像

此篇博客将介绍如何使用 Docker 创建一个alpine3.10-jre1.8.0_401 的 Docker 镜像&#xff0c;并使用 Docker 运行起来。将用到 Dockerfile 的 COPY 命令、RUN 命令、ENV 命令&#xff0c;最终实现基于单一应用的 Dockerfile 构建镜像和运行。 紧急修改&#xff1a;代码我是在m…

代码随想录第27天| 39. 组合总和

39. 组合总和 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 带你学透回溯算法-组合总和&#xff08;对应「leetcode」力扣题目&#xff1a;39.组合总和&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩_bilibili 给你一个 无重复元…

理解 SQL 数据添加:从基础到实践

引言&#xff1a; 在现代软件开发中&#xff0c;数据库是不可或缺的一部分。而 SQL 作为结构化查询语言的代表&#xff0c;广泛应用于数据库管理系统中&#xff0c;为我们提供了强大的数据管理和查询能力。 主题&#xff1a; 我们将从基础的 SQL INSERT INTO 语句开始&…

使用Pollard_rho算法分解质因数

分解质因数的朴素算法 最简单的算法即为从 [2, sqrt&#xff08;N&#xff09;] 进行遍历。 vector<int> breakdown(int N) {vector<int> result;for (int i 2; i * i < N; i) {if (N % i 0) { // 如果 i 能够整除 N&#xff0c;说明 i 为 N 的一个质因子。…

鸿蒙原生应用开发-网络管理Socket连接(一)

一、简介 Socket连接主要是通过Socket进行数据传输&#xff0c;支持TCP/UDP/TLS协议。 二、基本概念 Socket&#xff1a;套接字&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。 TCP&#xff1a;传输控制协议(Transmission Control Protocol)。是一…

HarmonyOS 应用开发之Worker

Worker主要作用是为应用程序提供一个多线程的运行环境&#xff0c;可满足应用程序在执行过程中与主线程分离&#xff0c;在后台线程中运行一个脚本操作耗时操作&#xff0c;极大避免类似于计算密集型或高延迟的任务阻塞主线程的运行。 Worker运作机制 图1 Worker运作机制示意…

联通iccid 19转20 使用luhn 算法的计算公式

联通iccid 19转20 使用luhn 算法的计算公式 第一次对接iccid 才知道 使用的是luhn 算法 19转20位 文章来源于 文章来源 当时也是一脸懵逼 的状态&#xff0c;然后各种chatgpt 寻找&#xff0c;怎么找都发现不对&#xff0c;最后看到这片java的文章实验是正确的&#xff0c;因…

MySQL 进阶-----索引使用规则

目录 前言 一、验证索引效率 二、最左前缀法则 三、范围查询 四、索引失效情况 1.索引列运算 2.字符串不加引号 3 .模糊查询 4.or连接条件 5 .数据分布影响 前言 本期我们学习MySQL索引的使用方法&#xff0c;在讲解索引的使用原则之前&#xff0c;先通过一个简单的…

JavaSE——面向对象高级三(5/5)-泛型方法、泛型的通配符、泛型擦除和注意事项

目录 泛型方法 泛型的通配符 泛型擦除和注意事项 泛型方法 修饰符 <类型变量,类型变量,...> 返回值类型 方法名(形参列表){ } public static <T> void test(T t){} 注意&#xff1a;下面这种不是泛型方法 public E get(int index){return (E) arr[index]; } 具体…