Qt 加载QSS文件(包括同时加载多个QSS文件)

Qt 加载qss文件

一、常规加载

常规加载的情况:项目简单只需要读取一个qss文件,或者根据不同需要在不用情况下读取多个qss文件中的一个文件。

情况一:项目简单只需要读取一个qss文件

具体代码:
在这里插入图片描述

#include 

Tip::Tip(QWidget *parent) :
    QDialog (parent),
    ui(new Ui::Tip)
{
    ui->setupUi(this);
	QFile qss(":/qss/qss_light.qss");
    if (qss.open(QFile::ReadOnly)){
        qApp->setStyleSheet( qss.readAll());
    }
}

情况二:读取多个qss文件中的一个文件

具体代码:

void LoadStyle::LoadStyleFile(QString strStyle)
{
	QFile qss(strStyle);
	qss.open(QFile::ReadOnly);
	qApp->setStyleSheet(qss.readAll());
	qss.close();
}

在主界面初始化时,调用这个函数,并把资源文件也就是QSS文件路径传进去:

m_cLoadStyle.LoadStyleFile(":/CTreeWidgetPro/Resource/Qss/CTreeWidgetPro.qss");
m_cLoadStyle.LoadStyleFile(":/CTreeWidgetPro/Resource/Qss/CustomItem.qss");

二、加载多个qss文件

方法一:多个样式文件放在同一个文件夹中一次获取

加载所有QSS文件大致思路是将QSS文件所在的文件夹下的所有样式文件都一次获取,循环读文件里面的内容,然后保存在一个字符串变量中,最后直接调用qApp->setStyleSheet()这个函数。

void LoadStyle::LoadStyleFile()
{
	QString strDirPath = ":/CTreeWidgetPro/Resource/Qss";
	QStringList strListStyleFiles = QDir(strDirPath).entryList(QDir::Files);
	QString strStyle = GetAllStyle(strListStyleFiles, strDirPath);
	qApp->setStyleSheet(strStyle);
}
QString LoadStyle::GetAllStyle(QStringList strListStyleFiles, QString strDirPath)
{
	if (!strDirPath.endsWith("/"))
	{
		strDirPath.append("/");
	}
	QString strStyle;
	for (auto strFileName : strListStyleFiles)
	{
		QFile fileRead(strDirPath + strFileName);
		if (fileRead.open(QFile::ReadOnly))
		{
			strStyle += QLatin1String(fileRead.readAll());
		}
		fileRead.close();
	}
	return strStyle;
}

LoadStyleFile()函数中,strDirPath变量是QSS文件所在的文件夹;strListStyleFiles保存了文件夹下面所有文件的文件名称;
GetAllStyle()函数中,在for循环中处理每一个文件名,将文件夹路径+文件名就组成了完整了QSS文件路径,在进行读操作,将所有的文件读完之后保存并返回。

m_cLoadStyle.LoadStyleFile();

最后只要在主界面调用这个LoadStyleFile();函数即可:
m_cLoadStyle是加载资源文件类的对象,不管资源文件夹下面多少个QSS样式文件,都只需要调用一次即可,后续资源文件中继续添加新的QSS文件,这部分代码也不用进行修改。

方法二:多个Qss文件动态加载

软件QssEditor的样式编辑器,他里面有一种很神奇的颜色用法。

QLabel {
 color:#FF0000;
}
QPushButton{
 color:#FF0000;
}

假如我有一个红色字体软件,现在有个场景需要把红色都改成绿色。

QLabel {
 color:#00FF00;
}
QPushButton{
 color:#00FF00;
}

正常做法是准备两份样式red.qss和green.qss,需要什么颜色我就加载什么样式。

但是借鉴下QssEditor里面的做法,就是用theme值替换原有值

QLabel {
 color:$FontColor;
}
QPushButton{
 color:$FontColor;
}

在代码里面把$FontColor替换成对应颜色

QFile file("style.qss");
    if (file.open(QIODevice::ReadOnly))
    {
        QMap<QString, QString> theme;
        theme.insert("$FontColor", "#FF0000");

        QString style = file.readAll();
        for(const QString& key : theme)
        {
            style.replace(key, theme[key]);
        }
        qobject_cast<QApplication*>(QApplication::instance())->setStyleSheet(style);
        file.close();
    }

如果是theme更改成全局变量,可以达到程序即使在运行中,也可以动态去修改颜色。

在大胆点使用的话,是不是可以将整按钮的样式都替换theme值

QLabel {
 color:#FF0000;
}
$ButtonStyle

把button的样式单独写成一份button.qss,在通过QFile写入到对应theme值

QFile file("style.qss");
    if (file.open(QIODevice::ReadOnly))
    {
        QMap<QString, QString> theme;
        QFile f("button.qss");
        if (f.open(QIODevice::ReadOnly))
        {
            theme.insert("$ButtonStyle", f.readAll());
        }
        else {
            theme.insert("$ButtonStyle", "");
        }

        QString style = file.readAll();
        for(const QString& key : theme)
        {
            style.replace(key, theme[key]);
        }
        qobject_cast<QApplication*>(QApplication::instance())->setStyleSheet(style);
        file.close();
    }

那这样操作的话,一个类型的控件我就单独封装成一个qss样式文件,在集中替换到style.qss文本。

是不是只需要一个配置单,配置好每个theme值对应的qss样式文件名

$LabelStyle=label.qss
$ButtonStyle=button.qss
...

这样就代码只需要加载一个配置单和一个style.qss文件就可以,其他的控件样式文件动态的加载到界面上。

注意,如果样式中出现theme值没被正确替换,会导致theme值之后的所有样式失效。

下面就可以正式版本

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define STYLE_SHEET_PATH "style.qss"
#define STYLE_SHEET_CONFIG "style.ini"
void realRefreshTheme(QString &style)
{
    QMap<QString, QString> theme;
    QSettings settings(STYLE_SHEET_CONFIG);
    for(const QString& key : settings.allKeys())
    {
        const QString &path = settings.value(key).toString();
        QFile file(path);
        if (file.open(QIODevice::ReadOnly))
        {
            theme.insert(key, file.readAll());
        }
        else {
            theme.insert(key, "");
        }
    }
    for(const QString& key : theme.keys())
    {
        style.replace(key, theme[key]);
    }
}

void realRefreshStyle()
{
    static QTimer timer;
#ifdef QT_DEBUG
    timer.setSingleShot(false);
#else
    timer.setSingleShot(true);
#endif
    QObject::connect(&timer, &QTimer::timeout, []() {
        static QDateTime dateTime;
        QFileInfo fileInfo(STYLE_SHEET_PATH);
        if (fileInfo.exists())
        {
            QDateTime fileTime = fileInfo.lastModified();
            if (dateTime == fileTime)
                return;
            dateTime = fileTime;

            QFile file(STYLE_SHEET_PATH);
            if (file.open(QIODevice::ReadOnly))
            {
                QString style = file.readAll();
                realRefreshTheme(style);
                qobject_cast<QApplication*>(QApplication::instance())->setStyleSheet(style);
                file.close();
            }
        }
    });
    timer.start(33);
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget win;
    win.show();
    realRefreshStyle();
    return app.exec();
}

下面是优化版本

#include 
#include 
#include 
#include 

#define STYLE_SHEET_PATH "style.qss"
#define STYLE_SHEET_CONFIG "style.ini"
void realRefreshTheme(QString &style)
{
    QMap<QString, QString> theme;
    QSettings settings(STYLE_SHEET_CONFIG);
    for(const QString& key : settings.allKeys())
    {
        const QString &path = settings.value(key).toString();
        QFile file(path);
        if (file.open(QIODevice::ReadOnly))
        {
            theme.insert(key, file.readAll());
        }
        else {
            theme.insert(key, "");
        }
    }
    for(const QString& key : theme.keys())
    {
        style.replace(key, theme[key]);
    }
}

void realRefreshStyle()
{
    QFile file(STYLE_SHEET_PATH);
    if (file.open(QIODevice::ReadOnly))
    {
       QString style = file.readAll();
       realRefreshTheme(style);
       qobject_cast<QApplication*>(QApplication::instance())->setStyleSheet(file.readAll());
       file.close();
    }
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;
    w.show();
#ifdef QT_DEBUG
    QFileSystemWatcher fileWatcher;
    fileWatcher.addPath(STYLE_SHEET_PATH);
    fileWatcher.addPath(STYLE_SHEET_CONFIG);
    QObject::connect(&fileWatcher, &QFileSystemWatcher::fileChanged, [](){
        realRefreshStyle();
    });
#else
    realRefreshStyle();
#endif
    return a.exec();
}

个人因项目需要从只需要加载单个QSS样式文件变为读取三个QSS文件(总QSS,分QSS1,分QSS2),且读取方式为总QSS+分QSS1,或者总QSS+分QSS2,所以本人更推荐最后一种方法

关于本人项目需求的解决方法代码如下:

//m_styleQssFile代表分QSS1,分QSS2的路径

void widget::slot_choose_qss()
{
	QFile file(":/Resources/universal.qss");
    if (file.open(QIODevice::ReadOnly))
    {
        QString lVarStyle;
        QFile f(m_styleQssFile);
        if (f.open(QIODevice::ReadOnly))
        {
            lVarStyle  = f.readAll();
        }
        else {
        }

        QString style = file.readAll();

        style = style.replace(QString("$myStyle"), lVarStyle);

        file.close();
        qobject_cast<QApplication*>(QApplication::instance())->setStyleSheet(style);
    }
}
这里有个小插曲,本人套用最后一种方法时,QMap传递值的时候出现了差错,但代码未报错,因时间紧迫未去探索原因,选择QString去代替QMap的功能,且已经可以满足项目需求。希望这些可以帮助到有需要的你们~

你可能感兴趣的:(Qt随笔,qt,ui,开发语言)