QML实现换肤(主题样式切换)
Qt Quick 没有像 QtWidgets 那样的 QSS 样式表机制,只能通过自定义组件或者设置 Controls 主题来实现样式定制。目前网上搜到的换肤功能,大多是定义一个全局的样式文件,在自定义组件中绑定全局样式属性,切换主题时更换全局属性的值。详情可参考 TaoQuick 中的换肤:Qml组件化编程3-动态切换皮肤 - 知乎
//Skin.qml 单例
pragma Singleton
import QtQuick 2.12
QtObject {
property string theme: "default"
property color bgColor: "gray"
onThemeChanged: {
if(theme=="dark"){
bgColor = "black"
}else{
bgColor = "gray"
}
}
}
//MyRecangle.qml 绑定单例中的属性
import QtQuick 2.12
Rectangle {
color: Skin.bgColor
}
当样式较为复杂时,这个全局配置文件可能会很大。我倾向于将不同的主题拆开,这样修改或新增某个主题时只改对应主题的配置文件不影响已有的代码。 同时,每个组件对应自己的样式集类型,这样就不会错误的绑定到其他的组件样式上去,IDE 智能提示看起来也更方便。
效果展示:
代码链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/QmlSkin
代码结构:
主要代码:
//RectangleStyle.qml 组件需要的样式属性在style中定义
import QtQuick 2.12
QtObject {
property color bgColor: "lightgray"
}
//SkinBase.qml 皮肤基类,定义默认样式
import QtQuick 2.12
QtObject {
//基本组件样式,默认绑定基本样式
property RectangleStyle rectangle: RectangleStyle{}
property ButtonStyle button: ButtonStyle{}
//特殊样式,根据需求扩展和绑定
property ButtonStyle redButton: ButtonStyle{
bgNormalColor: "red"
}
}
//SkinSkyBlue.qml 具体的皮肤样式,单例
pragma Singleton
import QtQuick 2.12
SkinBase { //继承自基类,设置对应的属性值
rectangle.bgColor: "mintcream"
}
//SkinManager.qml 管理皮肤的单例
pragma Singleton
import QtQuick 2.12
QtObject {
//当前皮肤选择,通过切换该值完成皮肤切换
property SkinBase currentSkin: SkinNormal
}
//EasyRectangle.qml 自定义组件,绑定到主题的对应样式
import QtQuick 2.12
Rectangle {
property RectangleStyle skin: SkinManager.currentSkin.rectangle
color: skin.bgColor
}