Qt 样式表语法

60 阅读7分钟

样式规则

样式表由一系列样式规则组成。样式规则由选择器和声明组成。选择器指定受规则影响的部件;声明指定应在部件上设置哪些属性。例如

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)中使用它们的尝试都将不起作用。

样式表参考Qt Style Sheets Reference | Qt Widgets | Qt 6.10.0