样式表语法

Qt 样式表的术语和语法规则几乎与 HTML CSS 相同。如果您已经了解 CSS,也许可以快速浏览本节内容。

样式规则

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

QPushButton { color: red }

在上述样式规则中,QPushButton 是选择器,{ color: red } 是声明。该规则指定QPushButton 及其子类(如MyPushButton )应使用红色作为前景色。

Qt XML 样式表一般不区分大小写(即color,Color,COLOR, 和cOloR 指的是同一个属性)。唯一的例外是类名、object names 和 Qt 属性名,它们区分大小写。

可以为同一声明指定多个选择器,使用逗号 (,) 分隔选择器。例如,规则

相当于由三条规则组成的序列:

QPushButton { color: red }
QLineEdit { color: red }
QComboBox { color: red }

样式规则的声明部分是一系列 property: value对的列表,用大括号 ({}) 括起来,中间用分号隔开。例如

QPushButton { color: red; background-color: white }

有关 Qt Widget 提供的属性列表,请参阅下面的属性列表部分。

选择器类型

到目前为止,所有示例都使用了最简单的选择器类型,即类型选择器。Qt 样式表支持CSS2 中定义的所有选择器。下表总结了最有用的选择器类型。

选择器示例说明
通用选择器*匹配所有部件。
类型选择器QPushButton匹配QPushButton 及其子类的实例。
属性选择器QPushButton[flat="false"]匹配非flatQPushButton 实例。您可以使用此选择器来测试任何支持QVariant::toString() 的 Qt属性(详情请参见toString() 函数文档)。此外,还支持用于类名称的特殊class 属性。

该选择器也可用于测试动态属性。有关使用动态属性进行自定义的更多信息,请参阅使用动态属性进行自定义

您也可以使用~= 代替= 来测试QStringList 类型的 Qt XML 属性是否包含给定的QString

警告: 如果 Qt 属性的值在样式表设置后发生变化,可能需要强制重新计算样式表。一种方法是取消设置样式表,然后重新设置。

类选择器.QPushButton匹配QPushButton 的实例,但不匹配其子类。

这等同于*[class~="QPushButton"]

ID 选择器QPushButton#okButton匹配object nameokButton 的所有QPushButton 实例。
后代选择器QDialog QPushButton匹配作为QDialog 的后代(子女、孙子女等)的QPushButton 的所有实例。
子女选择器QDialog > QPushButton匹配作为QDialog 直接子代的所有QPushButton 实例。

子控件

为复杂的 widget 设计样式时,有必要访问 widget 的子控件,如QComboBox 的下拉按钮或QSpinBox 的上下箭头。选择器可包含控件,以便将规则的应用限制在特定 widget 子控件上。例如

QComboBox::drop-down { image: url(dropdown.png) }

上述规则为所有QComboBoxes 的下拉按钮设置样式。尽管双引号(:: )语法让人联想到 CSS3 的伪元素(Pseudo-Elements),但 Qt 子控件在概念上与之不同,并具有不同的层叠语义。

子控件总是相对于另一个元素(参考元素)进行定位。这个参考元素可以是 widget,也可以是另一个子控件。例如,QComboBox::下拉默认放置在QComboBox 的 "填充 "矩形的右上角。::下拉默认放置在::下拉子控件的 "内容 "矩形的中心。有关用于样式化部件的子控件及其默认位置,请参阅下面的 "样式化部件列表"。

可以使用子控件-原点属性更改要使用的原点矩形。例如,如果我们想将下拉菜单放在QComboBox 的边距矩形中,而不是默认的填充矩形中,我们可以指定:

QComboBox {
    margin-right: 20px;
}
QComboBox::drop-down {
    subcontrol-origin: margin;
}

下拉菜单在边距矩形内的对齐方式可通过子控件-位置属性进行更改。

宽度高度属性可用于控制子控件的大小。请注意,设置图像会隐式地设置子控件的大小。

相对定位方案(position: relative)允许从初始位置偏移子控件的位置。例如,当按下QComboBox 的下拉按钮时,我们可能希望里面的箭头偏移,以产生 "按下 "的效果。为此,我们可以指定

QComboBox::down-arrow {
    image: url(down_arrow.png);
}
QComboBox::down-arrow:pressed {
    position: relative;
    top: 1px; left: 1px;
}

绝对定位方案(position: absolute)允许改变子控件相对于参考元素的位置和大小。

一旦定位,它们就会被视为与部件相同,并可使用框模型进行样式设计。

有关支持的子控件列表,请参阅下面的子控件列表,以及自定义 QPushButton 的菜单指示器子控件的实际示例。

注: 对于QComboBoxQScrollBar 等复杂部件,如果定制了一个属性或子控件,则必须同时定制所有其他属性或子控件。

伪状态

选择器可能包含伪状态,表示根据部件的状态限制规则的应用。伪状态出现在选择器的末尾,中间是冒号(: )。例如,当鼠标悬停在QPushButton 上时,以下规则适用:

QPushButton:hover { color: white }

伪状态可以使用感叹号运算符进行否定。例如,当鼠标没有悬停在QRadioButton 上时,以下规则适用:

QRadioButton:!hover { color: red }

伪状态可以是链式的,在这种情况下隐含逻辑 AND。例如,当鼠标悬停在选中的QCheckBox 上时,以下规则适用:

QCheckBox:hover:checked { color: white }

被否定的伪状态可以出现在伪状态链中。例如,当鼠标悬停在未按下的QPushButton 上时,以下规则适用:

QPushButton:hover:!pressed { color: blue; }

如果需要,可以使用逗号运算符来表示逻辑 OR:

QCheckBox:hover, QCheckBox:checked { color: white }

伪状态可以与子控件组合出现。例如

QComboBox::drop-down:hover { image: url(dropdown_bright.png) }

有关 Qt Widgets 提供的伪状态列表,请参阅下面的 "伪状态列表 "部分。

冲突解决

当多个样式规则指定了具有不同值的相同属性时,就会出现冲突。请看下面的样式表:

QPushButton#okButton { color: gray }
QPushButton { color: red }

两个规则都匹配名为okButtonQPushButton 实例,而color 属性存在冲突。要解决这一冲突,我们必须考虑选择器的特殊性。在上例中,QPushButton#okButton 被认为比QPushButton 更具体,因为它(通常)指的是单个对象,而不是一个类的所有实例。

同样,带有伪状态的选择器比不指定伪状态的选择器更具体。因此,下面的样式表规定,当鼠标悬停在QPushButton 上时,应显示白色文本,否则显示红色文本:

QPushButton:hover { color: white }
QPushButton { color: red }

这是一个棘手的问题:

QPushButton:hover { color: white }
QPushButton:enabled { color: red }

在这里,两个选择器具有相同的特定性,因此如果鼠标悬停在按钮上,而按钮处于启用状态,则第二条规则优先。如果我们希望在这种情况下文字是白色的,我们可以这样重新排列规则:

QPushButton:enabled { color: red }
QPushButton:hover { color: white }

或者,我们可以让第一条规则更具体:

QPushButton:hover:enabled { color: white }
QPushButton:enabled { color: red }

类型选择器也会产生类似的问题。请看下面的例子:

QPushButton { color: red }
QAbstractButton { color: gray }

两条规则都适用于QPushButton 实例(因为QPushButton 继承于QAbstractButton ),因此颜色属性存在冲突。因为QPushButton 继承了QAbstractButton ,所以可能会认为QPushButtonQAbstractButton 更具体。但是,对于样式表计算,所有类型选择器都具有相同的具体性,最后出现的规则优先。换句话说,所有QAbstractButtons(包括QPushButtons)的颜色都被设置为gray 。如果我们真的希望QPushButtons 显示红色文本,我们可以对规则重新排序。

在确定规则的特殊性时,Qt 样式表遵循CSS2 规范

选择器的特异性计算方法如下:

  • 计算选择器中 ID 属性的数量 (= a)
  • 计算选择器中其他属性和伪类的数量 (= b)
  • 计算选择器中元素名称的数量(= c)
  • 忽略伪元素[即子控件]。

将 a-b-c 这三个数字连接起来(在基数较大的数字系统中),就得到了特异性。

举例如下

*             {}  /* a=0 b=0 c=0 -> specificity =   0 */
LI            {}  /* a=0 b=0 c=1 -> specificity =   1 */
UL LI         {}  /* a=0 b=0 c=2 -> specificity =   2 */
UL OL+LI      {}  /* a=0 b=0 c=3 -> specificity =   3 */
H1 + *[REL=up]{}  /* a=0 b=1 c=1 -> specificity =  11 */
UL OL LI.red  {}  /* a=0 b=1 c=3 -> specificity =  13 */
LI.red.level  {}  /* a=0 b=2 c=1 -> specificity =  21 */
#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 (以及任何子部件)使用蓝色文本,尽管整个应用程序样式表提供了更具体的规则集。

如果我们编写的是

myPushButton->setStyleSheet("color: blue");

只不过,如果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() 所做的更改会被继承。如果没有明确设置相应的笔刷或字体,所有现有和未来的子部件都会继承这些更改。

C++ 命名空间内的小工具

类型选择器可用于样式化特定类型的部件。例如

classMyPushButton :publicQPushButton{// ...}// ...qApp->setStyleSheet("MyPushButton { background: yellow; }");

Qt 样式表使用部件的 QObject::className() 来决定何时应用类型选择器。当自定义 widget 位于名称空间内时,QObject::className() 会返回 <namespace>::<classname>。这与子控件的语法冲突。为了克服这个问题,当对名称空间内的部件使用类型选择器时,我们必须将:: 替换为-- 。例如

namespacens {classMyPushButton :publicQPushButton{// ...} }// ...qApp->setStyleSheet("ns--MyPushButton { background: yellow; }");

设置 QObject 属性

从 4.3 及以上版本开始,可使用 qproperty-<property name> 语法设置任何可设计的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)中使用它们的尝试都将不起作用。

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.