初学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); |
| |
| |
| static void setQssFileListRootFile(const QString &QssRootFile); |
| static QString getQssFileListRootFile(); |
| |
| |
| static void LoadQss2RefreshStyle(); |
| |
| |
| static void WatchQSSFileChange(QFileSystemWatcher *FileWatcher); |
| |
| private : |
| |
| |
| static QString m_QssRootFile; |
| |
| |
| static QString m_currentPath; |
| }; |
| |
| |
| #endif |
复制
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(); |
| } |
| } |
| |
| |
| QObject::connect(FileWatcher, &QFileSystemWatcher::fileChanged, [](){ |
| QssLoadTool::LoadQss2RefreshStyle(); |
| }); |
| } |
复制
main.cpp中使用方式:
| int main(int argc, char *argv[]) |
| { |
| QApplication a(argc, argv); |
| |
| |
| QString currentPath = QCoreApplication::applicationDirPath(); |
| |
| |
| QDir::setCurrent(currentPath); |
| |
| |
| QssLoadTool::setQssFileListRootFile(currentPath + "/../res/QSS/StyleList.txt"); |
| |
| 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)
