QSS使用规则

QSS介绍

QSS称为Qt Style Sheets也就是Qt样式表,它是Qt提供的一种用来自定义控件外观的机制。QSS大量参考了CSS的内容,只不过QSS的功能比CSS要弱很多,体现在选择器要少,可以使用的QSS属性也要少很多,并且并不是所有的属性都可以用在Qt的所有控件上。


语法规则

QSS的语法规则几乎与CSS相同。一条QSS的样式是由两部分组成的,一部分是选择器指定了哪些控件会受到影响,另一部分是指定了属性的值,表示这些控件的哪些属性会受到影响。例如:
QPushButton { color: red }
QPushButton表示选择器,指定了所有的QPushButton或者是QPushButton的子类会受到影响。而后面的{color:red}则是规则的定义,表明指定前景颜色是红色。整个意思就是设置QPushButton类以及其子类的所有实例的前景色是红色。


选择器类型

1.通配选择器:* ; 匹配所有的控件
2.类型选择器:QPushButton ; 匹配所有QPushButton和其子类的实例
3.属性选择器:QPushButton[flat=”false”]; 匹配所有flat属性是false的QPushButton实例,注意该属性可以是自定义的属性,不一定非要是类本身具有的属性
4.类选择器: .QPushButton ; 匹配所有QPushButton的实例,但是并不匹配其子类。这是与CSS中的类选择器不一样的地方,注意前面有一个点号
5.ID选择器: #myButton; 匹配所有id为myButton的控件实例,这里的id实际上就是objectName指定的值
6.后代选择器: QDialog QPushButton ; 所有QDialog容器中包含的QPushButton,不管是直接的还是间接的
7.子选择器: QDialog > QPushButton; 所有QDialog容器下面的QPushButton,其中要求QPushButton的直接父容器是QDialog
另外上面所有的这些选择器可以联合使用,并且支持一次设置多个选择器类型,用逗号隔开,这点与CSS一样。


QSS子控件

QSS的子控件实际上也是选择器的一种,因为这种选择器与CSS有一些不同,所以单独拿出来说,QSS的子控件选择器是应用在一些复合控件上的,典型的例如QComboBox,该控件的外观包含几个部分,一般情况下有一个矩形的外边框,右边有一个向下的箭头用于提示点击之后会有弹出下拉列表。例如:
QComboBox::drop-down { image: url(dropdown.png) }
上面的样式指定所有QComboBox的下拉箭头的图片为自定义的图片dropdown.png
::dropdown子控件选择器也可以与上面提到的选择器一起联合使用:
QComboBox#myQComboBox::drop-down { image: url(dropdown.png) }
指定id名为myQComboBox的QComboBox控件的下拉箭头的自定义图片,要注意的是子控件选择器实际上是选择复合控件中的一部分,也就是说对复合控件中的一部分应用样式,例如为QComboBox的下拉箭头指定图片,而不是为QComboBox本身指定图片。


QSS伪状态

QSS的伪状态选择器实际上与CSS中的类似,是以冒号开头的一个选择表达式,例如:hover表示当鼠标经过时候的状态。他限制了当控件在某一种状态下的时候才能应用QSS规则,伪状态只能描述一个控件的状态,或者是一个复合控件中的子控件的状态,所以该伪状态选择器只能放在选择器的最后面,例如:
QComboBox:hover{background-color:red;}
该规则表示当鼠标经过QComboBox上面的时候,其背景颜色指定为红色,该伪状态 :hover描述的是QComboBox的状态。
伪状态除了描述选择器选择的控件以外,还可以描述子控件选择器所选择的复合控件中的子控件的状态,例如:
QComboBox::drop-down:hover{background-color:red;}
表示当鼠标经过QComboBox的下拉箭头的时候,该下拉箭头的背景颜色变成红色。
此外伪状态可以用一个感叹号表示否,例如:hover表示鼠标经过,而:!hover表示鼠标没有经过的状态。几个伪状态可以同时一起使用,例如:
QCheckBox:hover:checked { color: white }
指定一个当鼠标经过一个选中的QCheckBox的时候,设置其文字的前景颜色为白色。


QSS级联与冲突

QSS中的级联包含几个方面的概念,一个是当在同一个控件上应用两个不同的规则,那么应该应用哪一个规则的问题,也就是如何解决这种冲突。二个是在一个容器控件上设置的QSS规则会对容器里面的控件产生效果(这要取决于容器控件上设置的QSS规则是什么样的规则,如果容器控件上设置的QSS规则仅仅针对容器控件本身则该规则对子控件没有影响,如果该QSS规则里面有对子控件的设置,则自然会对子控件产生效果),级联问题是解决当一个控件被层层父容器包裹,并且在每一层的父容器上都有对该控件的样式设置的时候,该控件的最终效果是合并这些父容器上的QSS效果。

冲突问题:
QPushButton#okButton { color: gray }
QPushButton { color: red }
这两条规则都会应用到名为okButton的按钮上,但是他们为同一个属性设置了不同的颜色,这会有冲突,那么要解决这样的冲突就必须考虑到选择器的特异性(这个词怎么理解,我理解为这个特异性为更加特殊,实际上CSS上用权重表示这里的特异性),显然QPushButton#okButton仅仅针对对象名为okButton的控件有效果,而QPushButton却对所有的QPushButton的实例或者是其子类的实例有效果,显然QPushButton#okButton选择器更加特殊,也就是更具有特异性。所以最终okButton前景色被应用为灰色。如果两条规则的特异性一样,那么就选择放在后面的那一条。

另外如果一个选择器应用了伪状态,而另一个没有,那么应用了伪状态的选择器要更加特殊,例如:
QPushButton:hover { color: white }
QPushButton { color: red }
显然QPushButton:hover比单纯的QPushButton更加具有特异性。这两条规则表示当鼠标放在按钮上的时候文字是白色,其他情况下都是红色。
如下面两个规则的特异性是一样的,那么应该是如何应用呢:
QPushButton:hover { color: white } //如果鼠标经过则前景白色
QPushButton:enabled { color: red } //如果按钮是enabled状态则前景红色
所以默认情况下前景文字是红色的,当鼠标经过的时候并不会变成白色,因为他们的特异性是一样的,所以选择后面的,也就是红色。
那么换一下顺序会怎样呢:
QPushButton:enabled { color: red } //如果按钮是enabled状态则前景红色
QPushButton:hover { color: white } //如果鼠标经过则前景白色
当鼠标经过的时候,就变成白色的了,因为他们的特异性一样,所以选择后面的规则,也就是鼠标经过前景变成白色。
如果把其中的一条的特异性增加,例如:
QPushButton:hover:enabled { color: white }
QPushButton:enabled { color: red }
那么第一条的特异性比第二条大,所以应用第一条的规则。
另外一种特异性发生在类型选择器上:
QPushButton { color: red } //应用在所有的QPushButton上
QAbstractButton { color: gray } //应用在所有的QAbstractButton上
而在类的继承结构上,QAbstractButton是QPushButton的父类,显然QPushButton更加具有特异性,所以QPushButton的前景颜色被应用为红色,而不是灰色。


QSS常用设置

具体参考:http://doc.qt.io/qt-4.8/stylesheet-examples.html

(1)方箱模型
在样式表中,每个部件都被看作是一个由四个同心相似的矩形组成的箱体:空白(margin)、边框(border)、填充(padding)和内容(content)。对于一个平面部件——例如一个空白、边框和填充都是0像素的部件——而言,这四个矩形是完全重合的。
空白区域位于边框外,并且总是透明的。边框为部件提供了四周的框架,其border-style属性可以设置为一些内置的框架风格,如inset、outset、solid和ridge。填充在边框和内容区域之间提供了空白间隔。

(2)前景与背景
部件的前景色用于绘制上面的文本,可以通过color属性指定。背景色用于绘制部件的填充矩形,可以通过background-color属性指定。
背景图片使用background-image属性定义,它用于绘制由background-origin指定的矩形区域(空白、边框、填充或内容)。背景图片在矩形区域内的对齐和平铺方式可以通过background-position和background-repeat属性指定。
如果指定的背景图片具有alpha通道(即有半透明效果),通过background-color指定的颜色将会透过透明区域。这一功能可以使背景图片在多种环境下重复利用。
该例子中使用的样式表如下所示:

QFrame {
    margin: 10px;
    border: 2px solid green;
    padding: 20px;

    background-color: gray;
    background-image: url(qt.png);
    background-position: top right;
    background-origin: content;
    background-repeat: none;
}

我们也可以分别指定margin-top、margin-right、margin-bottom、margin-left四个属性。

QFrame {
    margin-top: 14px;
    margin-right: 18px;
    margin-bottom: 20px;
    margin-left: 18px;
}

(3)处理伪状态
部件的外观可以按照用户界面元素状态的不同来分别定义,这在样式表中被称为“伪状态”。例如,如果我们想在一个push button在被按下的时候具有sunken的外观,我们可以指定一个叫做 :pressed 的伪状态。

QPushButton {
    border: 2px outset green;
    background: gray;
}

QPushButton:pressed {
    border-style: inset;
}

下面是可用的伪状态列表:

表 1. 伪状态列表
伪状态 描述
:checked button部件被选中
:disabled 部件被禁用
:enabled 部件被启用
:focus 部件获得焦点
:hover 鼠标位于部件上
:indeterminate checkbox或radiobutton被部分选中
:off 部件可以切换,且处于off状态
:on 部件可以切换,且处于on状态
:pressed 部件被鼠标按下
:unchecked button部件未被选中

(4)使用子部件定义微观样式
许多部件都包含有子元素,这些元素可以称为“子部件”。Spin box的上下箭头就是子部件最好的例子。
子部件可以通过::来指定,例如QDateTimeEdit::up-button。定义子部件的样式与定义部件非常相似,它们遵循前面提到的方箱模型(即它们可以拥有自己的边框、背景等),并且也可以和伪状态联合使用(例如QSpinBox::up-button:hover)。
下表列出了可用的子部件类型:

表 2. 子部件列表
子部件 描述
::down-arrow combo box或spin box的下拉箭头
::down-button spin box的向下按钮
::drop-down combo box的下拉箭头
::indicator checkbox、radio button或可选择group box的指示器
::item menu、menu bar或status bar的子项目
::menu-indicator push button的菜单指示器
::title group box的标题
::up-arrow spin box的向上箭头
::up-button spin box的向上按钮

通过指定subcontrol-position和subcontrol-origin属性,子部件可以被放置在部件箱体内的任何位置。并且,子部件的位置还可以使用相对或绝对的方式进一步的调整。具体选择何种调整方式取决于子部件具有固定的大小,还是会随着父部件而变化。

<think>好的,用户问的是如何在QSS使用变量或者替代方案。我之前记得QSS本身不支持变量,但可能需要用其他方法来实现类似的效果。首先,我需要回忆一下Qt的样式表机制。QSS类似于CSS,但功能有限,比如确实没有变量支持。那用户可能需要动态设置样式或者通过其他途径复用样式值。 接下来,考虑替代方案。比如,用户可能想统一管理颜色、字体等样式属性。一个办法是使用Qt的资源文件(qrc)来定义颜色常量,但资源文件主要是管理文件路径,可能不适用。或者,可以在代码中定义颜色变量,然后在设置样式时拼接字符串。例如,定义一个全局的颜色字符串,然后在需要的地方引用它。 另外,QtConcurrent模块的引用中提到需要在.pro文件中添加QT += concurrent,这可能和QSS无关,但用户提供的引用中有内存管理和配置的内容,可能需要考虑资源的使用效率。例如,使用宏定义或者单例类来保存样式相关的变量,避免重复代码。 还有一种方法是使用Qt的属性系统。可以为QWidget设置动态属性,然后在QSS中根据属性值来应用样式。例如,设置一个自定义属性“mainColor”,然后在QSS使用attr(mainColor)来引用。不过,我需要验证这种方法是否可行,可能QSS不支持直接读取属性作为变量。 另外,用户提到的归一化公式可能和样式无关,但或许用户有动态计算样式的需求,比如根据数据调整颜色深浅。这时候可能需要结合C++代码生成QSS字符串,动态替换变量部分。 然后想到,可以使用QObject的属性或者动态属性。比如,在代码中设置某个对象的属性,然后在QSS中引用该属性。不过QSS是否支持这种动态属性呢?查文档的话,QSS支持根据对象属性选择样式,但不一定支持直接取值作为变量。 或者,使用预处理器。在编译前,用脚本处理QSS文件,替换其中的变量。这种方法需要构建系统的支持,比如在.pro文件中添加自定义步骤,用sed或其他工具替换变量。但这样会增加项目的复杂性,可能不是最佳方案。 还有一种可能是通过继承QProxyStyle来自定义样式,在代码中集中管理样式属性。这样可以在运行时动态调整样式,但需要更多的代码量。 另外,用户提供的引用[2]中提到了环境变量的配置,比如设置QT_MM_POOL_SIZE,这可能和内存管理有关,但或许可以启发使用环境变量来存储样式值?不过QSS是否支持读取环境变量呢?不确定,需要查证。通常QSS不支持环境变量,但可以通过在程序中读取环境变量,然后生成QSS字符串。 综合来看,最直接的替代方案可能是在代码中定义变量,构建QSS字符串时插入这些变量值。例如: ```cpp QString mainColor = "#FF0000"; QString style = QString("QWidget { color: %1; }").arg(mainColor); app.setStyleSheet(style); ``` 这样,通过C++变量来管理样式值,达到类似使用变量的效果。如果有多个变量,可以统一管理这些字符串,方便修改和维护。 另外,如果使用多个相似的样式,可以考虑使用函数或宏来生成样式字符串,减少重复代码。例如,定义一个函数返回带有特定颜色的样式字符串,然后在需要的地方调用该函数。 对于更复杂的动态需求,可能需要结合Qt的信号槽机制,在属性变化时重新应用样式。例如,当主题颜色改变时,重新生成并设置整个应用程序的样式表。 总结可能的解决方案: 1. 使用C++字符串变量拼接样式表。 2. 利用Qt的动态属性,根据属性选择不同的样式规则。 3. 使用预处理器在构建时替换QSS中的变量。 4. 集中管理样式字符串,通过函数生成样式表。 5. 结合Qt样式类(QProxyStyle)自定义绘制逻辑。 需要进一步验证这些方法的可行性,特别是动态属性和样式生成的部分。同时,用户可能希望尽量减少代码改动,所以推荐使用第一种方法,即在代码中用变量生成样式表,这样简单直接。</think>在QSS中实现变量功能可通过以下方法实现: ### 一、QSS变量替代方案 1. **字符串模板方法**(推荐方案) ```cpp // 定义颜色变量 const QString PRIMARY_COLOR = "#2CA7F8"; const QString FONT_FAMILY = "Microsoft YaHei"; // 构建样式表 QString styleSheet = QString(R"( QPushButton { background: %1; font-family: %2; } QLabel#title { color: %1; } )").arg(PRIMARY_COLOR, FONT_FAMILY); qApp->setStyleSheet(styleSheet); ``` *优势*:编译时类型检查,IDE支持自动补全,方便重构[^2] 2. **JSON配置法** ```json // style_config.json { "@primary_color": "#2CA7F8", "@font_size": "14px" } ``` ```cpp // 加载配置 QFile configFile(":/style_config.json"); configFile.open(QIODevice::ReadOnly); QJsonDocument config = QJsonDocument::fromJson(configFile.readAll()); // 动态替换 QString style = loadStyleSheet().replace("@primary_color", config["primary_color"].toString()); ``` ### 二、动态属性方案 ```cpp // 设置控件属性 widget->setProperty("customColor", QColor(44, 167, 248)); // QSS使用 QPushButton { color: attr(customColor); } ``` *注意*:需要继承QStyle并重载drawControl()实现属性解析[^1] ### 三、预处理器方案 1. 安装Sass预处理工具 2. 创建qss变量文件: ```scss $primary: #2CA7F8; $padding: 8px; QPushButton { padding: $padding; border: 1px solid darken($primary, 10%); } ``` 3. 编译命令: ```bash sass --watch style.scss:style.qss ``` ### 四、Qt元对象系统方案 ```cpp class StyleManager : public QObject { Q_OBJECT Q_PROPERTY(QString primaryColor READ primaryColor NOTIFY themeChanged) public: static StyleManager* instance() { static StyleManager _instance; return &_instance; } // ... 属性访问方法 }; // QSS使用 QPushButton { color: qproperty-primaryColor; } ``` **性能优化建议**: 1. 使用`QStyle::polish()`代替频繁设置样式表 2. 对全局样式启用`Qt::AA_UseStyleSheetPropagationInWidgetStyles`属性 3. 遵循内存管理优化配置[^2]: ```cpp qputenv("QT_NO_FT_CACHE", "1"); qputenv("QT_MM_POOL_SIZE", "2097152"); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值