为了满足不同客户对不同风格的皮肤要求,通常需要在程序中携带多种皮肤资源,这个时候我们就需要能够随时随地只发布新皮肤。
通常我的做法如下:
一、生成rcc文件
1. 每一个UI对应一个css样式文件(css基本等同于qss),为了方便管理,样式文件名称与UI类名一致。例如:
CLoginDlg.css
/*
登陆窗口样式表 CLoginDlg
*/
.CLoginDlg{
border:1px solid #4D4D4D;
border-radius:5px;
/*background-image:url(:/src/image/DlgLogin.bmp)*/
}
/*关闭按钮*/
QPushButton#btnClose{
border-image:url(:/src/image/denglu_close.bmp) 0 0 96 0;
}
QPushButton#btnClose:hover{
border-image:url(:/src/image/denglu_close.bmp) 24 0 72 0
}
QPushButton#btnClose:pressed{
border-image:url(:/src/image/denglu_close.bmp) 48 0 48 0
}
2. 所有UI对应的样式表文件编辑好了后,需要将他们添加到qrc资源文件中。可以利用QtCreator的向导新建qrc文件并且把样式表添加到qrc中,例如main.qrc中qss属性下的几个css后缀的文件:
main.qrc
<RCC>
<qresource prefix="/qss">
<file>stylesheet.css</file>
<file>CLoginDlg.css</file>
<file>CMsgBox.css</file>
</qresource>
<qresource prefix="/src">
<file>image/main.ico</file>
<file>image/DlgLogin.bmp</file>
<file>image/denglu_close.bmp</file>
<file>image/denglu_min.bmp</file>
<file>image/DlgLogin_set.bmp</file>
<file>image/checkbox.bmp</file>
<file>image/DlgLogin_login.bmp</file>
<file>image/xialazhishi.png</file>
<file>image/login_head.png</file>
<file>image/LOGIN_LIST_CLOSE.png</file>
<file>image/diseanniubeijing.bmp</file>
</qresource>
</RCC>
3. 将所有样式表中需要用到的图片资源、字体资源、音视频资源等等都添加到上述的main.qrc中,这一步可以利用向导去添加,节省时间。例如上述main.qrc中的png和bmp文件
4. 打开Qt的命令行工具,并cd到main.qrc所在的目录,输入以下命令:
rcc -binary main.qrc -o main.rcc
最终在生成了main.rcc文件,当然这个文件名可以任意的。
关于rcc的更多用法,可以参考QResource中的说明,或者直接在帮助文档中搜索rcc
5. 在开发的初期为了方便UI样式调整,可以将main.qrc添加到工程中,但是等到后期这套方案稳定了,就没必要将mian.qrc放到工程中,更不用将资源文件添加工程中,只需要rcc文件即可。这样可以减少exe文件大小。
6. 当需要增加新皮肤时,只需要按照上述的步骤,重新修改css、替换图片等等相关资源文件,然后重新生成rcc文件即可。
7. 每个css样式表中用到的资源,在main.qrc中必须能找得到,而且路径也不能错(符合Qt的qrc搜索路径规则,即 :/ 开头),否则样式不起作用,例如 :/src/image/denglu_close.bmp。
上面所提到的 main.qrc CLoginDlg.css等等,名称都可以随便取,内含的资源路径也可以随便放,但是main.qrc里面的css资源路径配置是一定不能变更的,因为代码里面是通过
QFile file(":/qss/CLoginDlg.css")去加载css文件并读取css中的内容,然后调用widget->setStyleSheet(css内容)去实现ui样式更换的。
二、使用rcc和换肤
1. 将rcc注册到系统中
CResourceHelpers::RegistUIResource("你的rcc路径");当然你可以把一个默认的rcc配置到系统中,随着exe一起打包,这样不至于没有rcc时界面难看,此时你的rcc路径可以写成一个资源路径。
2. 在每个UI类的构造函数中调用
CResourceHelpers::SetStyleSheet(this, "CLoginDlg");
这个调用一般紧跟在 setupUi()后面
3. 当每次切换皮肤时,只需要调用CResourceHelpers::RegistUIResource即可。
class CResourceHelpers
{
private:
static QString m_strRccFileName;
public:
CHelpers();
~CHelpers();
//注册UI资源rcc文件
static bool RegistUIResource(const QString& strResourceName)
{
if (!m_strRccFileName.isEmpty())
{
QResource::unregisterResource(QString("%1/skin/%2")
.arg(qApp->applicationDirPath())
.arg(m_strRccFileName));
}
m_strRccFileName = strResourceName;
if (QResource::registerResource(QString("%1/skin/%2")
.arg(qApp->applicationDirPath())
.arg(m_strRccFileName)))
{
//加载全局的
QString qss = GetStyleSheet("stylesheet");
if (!qss.isEmpty())
{
qApp->setStyleSheet(qss);
}
return true;
}
return false;
}
//从rcc文件中加载qss,并设置到qwidget中
static bool SetStyleSheet(QWidget* pWidget, const QString& strQssName)
{
QString str = GetStyleSheet(strQssName);
if (str.isEmpty())
{
return false;
}
pWidget->setStyleSheet(str);
return true;
}
private:
static QString GetStyleSheet(const QString& strQssName)
{
QString strQss;
QFile file(QString(":/qss/%1.css").arg(strQssName));
if (file.open(QIODevice::ReadOnly))
{
strQss = QLatin1String(file.readAll());
file.close();
return strQss;
}
return strQss;
}
};