样式规则
样式表由一系列样式规则组成。样式规则由选择器和声明组成。选择器指定受规则影响的部件;声明指定应在部件上设置哪些属性。例如
QPushButton { color: red }
在上述样式规则中,QPushButton 是选择器,{ color: red } 是声明。该规则指定[QPushButton]及其子类(如MyPushButton )应使用红色作为前景色。
Qt XML 样式表一般不区分大小写(即color,Color,COLOR, 和cOloR 指的是同一个属性)。唯一的例外是类名、object names 和 Qt 属性名,它们区分大小写。
可以为同一声明指定多个选择器,使用逗号 (,) 分隔选择器。例如,规则
QPushButton, QLineEdit, QComboBox { color: red }
样式规则的声明部分是一系列 property: value对的列表,用大括号 ({}) 括起来,中间用分号隔开。例如
QPushButton { color: red; background-color: white }
选择器类型
| 选择器 | 示例 | 说明 |
|---|---|---|
| 通用选择器 | * | 匹配所有部件。 |
| 类型选择器 | QPushButton | 匹配QPushButton 及其子类的实例。 |
| 属性选择器 | QPushButton[flat="false"] | 匹配非flat 的QPushButton实例。您可以使用此选择器来测试任何支持QVariant::toString() 的 Qt属性(详情请参见toString() 函数文档)。 此外,还支持用于类名称的特殊 class 属性。该选择器也可用于测试动态属性。有关使用动态属性进行自定义的更多信息,请参阅使用动态属性进行自定义。您也可以使用~= 代替= 来测试QStringList类型的 Qt XML 属性是否包含给定的QString. 警告: 如果 Qt 属性的值在样式表设置后发生变化,可能需要强制重新计算样式表。一种方法是取消设置样式表,然后重新设置。 |
| 类选择器 | .QPushButton | 匹配QPushButton 的实例,但不匹配其子类。这等同于*[class~="QPushButton"] 。 |
| ID 选择器 | QPushButton#okButton | 匹配object name) 为okButton 的所有QPushButton 实例。 |
| 后代选择器 | QDialog QPushButton | 匹配作为QDialog的后代(子女、孙子女等)的QPushButton 的所有实例。 |
| 子女选择器 | QDialog > QPushButton | 匹配作为QDialog 直接子代的所有QPushButton 实例。 |
| 子控件选择器 | QComboBox::drop-down | 匹配QComboBox的drop-down子控件 |
| 伪状态选择器 | :hover | 选择器可能包含伪状态,表示根据部件的状态限制规则的应用。伪状态出现在选择器的末尾,中间是冒号(: )。Qt Widgets 提供的伪状态列表 |
注意:后代和子女选择器是其他选择器的组合集
冲突解决
在Qt样式表中,选择器的优先级规则与CSS类似。通常,选择器的优先级是根据其特异性(specificity)来决定的。特异性越高,优先级越高,相同特异性,最后出现的规则优先。内联样式(style属性)不计算特异性,高于样式表。
选择器的特异性计算方法如下:
- 计算选择器中 ID 属性的数量 (= a)
- 计算选择器中其他属性和伪类的数量 (= b)
- 计算选择器中元素名称的数量(= c)
- 忽略[子控件]。
- 后代和子女选择器的特异性是其他选择器的组合集
将 a-b-c 这三个数字连接起来(在基数较大的数字系统中),就得到了特异性。
假如a=100,b=10, c=1,则:
| 选择器类型 | 语法 | 优先级(特异性) | 使用场景 |
|---|---|---|---|
| 通用选择器 | * | 最低(0) | 全局基础样式 |
| 类型选择器 | QPushButton | 低(1) | 同类控件统一样式 |
| 伪状态 | :hover | 中(10) | 功能临时状态 |
| 类选择器 | .className | 中(10) | 按功能分组样式 |
| 属性选择器 | [attr=value] | 中(10) | 根据状态设置样式 |
| ID选择器 | #objectName | 高(100) | 特定控件定制样式 |
| 后代选择器 | A B | 继承父级(组合) | 层级结构中的控件 |
| 子女选择器 | A > B | 继承父级 (组合) | 直接子控件 |
举例说明:
通用选择器: * {} /* a=0 b=0 c=0 -> specificity = 0 */
1类型选择器: LI {} /* a=0 b=0 c=1 -> specificity = 1 */
2类型选择器: UL LI {} /* a=0 b=0 c=2 -> specificity = 2 */
3类型选择器: UL OL+LI {} /* a=0 b=0 c=3 -> specificity = 3 */
1类型选择器+1属性选择器:H1 + *[REL=up]{} /* a=0 b=1 c=1 -> specificity = 11 */
3类型选择器+1类选择器: UL OL LI.red {} /* a=0 b=1 c=3 -> specificity = 13 */
1类型选择器+2类选择器: LI.red.level {} /* a=0 b=2 c=1 -> specificity = 21 */
1ID选择器: #x34y {} /* a=1 b=0 c=0 -> specificity = 100 */
层叠
可以在QApplication、父部件和子部件上设置样式表。任意 widget 的有效样式表是通过合并 widget 祖先(父辈、祖辈等)上设置的样式表以及QApplication 上设置的任何样式表而获得的。
当出现冲突时,无论冲突规则的特殊性如何,部件自己的样式表总是优先于任何继承的样式表。同样,父 widget 的样式表也优先于祖辈的样式表,等等。
这样做的一个结果是,在部件上设置样式规则会自动使其优先于祖先部件样式表或QApplication 样式表中指定的其他规则。请看下面的例子。首先,我们在QApplication
qApp->setStyleSheet("QPushButton { color: white }");
然后,我们在QPushButton对象上设置样式表:
myPushButton->setStyleSheet("* { color: blue }");
QPushButton上的样式表会强制QPushButton(以及任何子部件)使用蓝色文本,尽管整个应用程序样式表提供了更具体的规则集。
样式表级联是一个复杂的话题。详情请参考CSS2 规范。请注意,Qt XML 目前并未实现!important
继承
在经典 CSS 中,如果未明确设置项目的字体和颜色,则会自动从父代继承。默认情况下,当使用 Qt 样式表时,部件不会自动从其父部件继承字体和颜色设置。
例如,请看QGroupBox 中的QPushButton
qApp->setStyleSheet("QGroupBox { color: red; } ");
QPushButton 没有明确的颜色设置。因此,它没有继承父QGroupBox 的颜色,而是使用系统颜色。如果我们要为QGroupBox 及其子代设置颜色,可以这样写
qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");
相反,使用QWidget::setFont() 和QWidget::setPalette() 设置字体和调色板会传播到子部件。 如果希望字体和调色板传播到子部件,可以设置Qt::AA_UseStyleSheetPropagationInWidgetStyles 标志,如下所示: 使用方法:
QCoreApplication::setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles, true);
启用widget样式的字体和调色板传播后,通过 Qt 样式表进行的字体和调色板更改将如同用户在样式表所针对的所有 QWidget 上手动调用相应的QWidget::setPalette() 和QWidget::setFont 方法一样。
- 样式表所做的更改会被传播。它们会在更改时一次性推送到与样式表匹配的所有部件上。
- 调用QWidget::setPalette() 或QWidget::setFont() 所做的更改会被继承。如果没有明确设置相应的笔刷或字体,所有现有和未来的子部件都会继承这些更改。
设置 QObject 属性
从 4.3 及以上版本开始,可使用 qproperty- 语法设置任何可设计的Q_PROPERTY 。 例如
MyLabel { qproperty-pixmap: url(pixmap.png); }
MyGroupBox { qproperty-titleColor: rgb(100, 200, 100); }
QPushButton { qproperty-iconSize: 20px 20px; }
如果属性引用了一个用Q_ENUM 声明的枚举,则应通过名称而不是数值来引用其常量。
注意: 请谨慎使用 qproperty 语法,因为它会修改正在绘制的 widget。此外,qproperty 语法只评估一次,即在使用样式打磨部件时。这意味着,任何在伪状态(如QPushButton:hover)中使用它们的尝试都将不起作用。