样式表语法
Qt 样式表的术语和语法规则几乎与 HTML CSS 相同。如果您已经了解 CSS,您可能可以快速浏览本节。
样式规则
样式表由一串样式规则组成。一个 样式规则 由一个选择器和一条声明组成。选择器指定受此规则影响的哪些小部件;声明指定小部件上应设置的哪些属性。例如
QPushButton { color: red }
在上面的样式规则中,QPushButton
是选择器,{ color: red }
是声明。该规则指定了 QPushButton 及其子类(例如,MyPushButton
)应将红色用作其前景色。
Qt 样式表通常不区分大小写(即,color
、Color
、COLOR
和 cOloR
指的是同一个属性)。唯一的例外是类名、对象名 和 Qt 属性名,这些都是大小写敏感的。
可以为相同的声明指定几个选择器,使用逗号 (,
) 来分隔选择器。例如,以下规则
QPushButton, QLineEdit, QComboBox { color: red }
与以下三个规则序列等效
QPushButton { color: red } QLineEdit { color: red } QComboBox { color: red }
样式规则的声明部分是一个由大括号 ({}
) 包围的 property: value
配对列表,并用分号分隔。例如
QPushButton { color: red; background-color: white }
有关 Qt 小部件提供的属性列表,请参阅下面的 属性列表 部分。
选择器类型
迄今为止的所有示例都使用了最简单的选择器类型,即类型选择器。Qt 样式表支持 CSS2 中定义的所有 选择器。下表总结了最有用的选择器类型。
选择器 | 示例 | 说明 |
---|---|---|
通用选择器 | * | 匹配所有小部件。 |
类型选择器 | QPushButton | 匹配 QPushButton 及其子类的实例。 |
属性选择器 | QPushButton[flat="false"] | 匹配不是 flat 的 QPushButton 的实例。您可以使用此选择器测试任何支持 QVariant::toString()(请参阅 toString() 函数文档以获取详细信息)的 Qt 属性。此外,支持特殊 class 属性,用于表示类名。此选择器也可用于测试动态属性。有关使用动态属性定制的信息,请参阅 使用动态属性定制。 与其使用 警告:如果样式表设置之后 Qt 属性的值发生变化,可能需要强制重新计算样式表。一种实现方式是先取消设置样式表,然后再重新设置。 |
类选择器 | .QPushButton | 匹配 QPushButton 的实例,但不是其子类的实例。 这等同于 |
ID 选择器 | QPushButton#okButton | 匹配所有 QPushButton 实例,其中 对象名称 为 okButton 。 |
后代选择器 | QDialog QPushButton | 匹配所有是 QDialog 后代(子、孙等)的 QPushButton 实例。 |
子元素选择器 | QDialog > QPushButton | 匹配所有是 QDialog 直接子元素的 QPushButton 实例。 |
子控制
对于复杂的控件样式化,需要访问控件的子控制,如 QComboBox 的下拉按钮或 QSpinBox 的上下箭头。选择器可以包含 子控制,使其能够将规则的适用范围限制到特定的控件子控制。例如
QComboBox::drop-down { image: url(dropdown.png) }
上述规则样式化了所有 QComboBox 的下拉按钮。尽管双冒号(::
)语法让人联想到 CSS3 伪元素,但 Qt 子控件的逻辑上与这些不同,具有不同的层叠语义。
子控件始终相对于另一个元素(一个参考元素)定位。这个参考元素可以是控件或另一个子控件。例如,::drop-down 默认放置在 QComboBox 的填充矩形的右上角。默认情况下,::drop-down 子控件位于其内容矩形的中心。有关用于样式化控件及其默认位置的子控件,请参阅下面的 可样式化控件列表。
可以使用 subcontrol-origin 属性来更改要使用的原始矩形。例如,如果我们想在 QComboBox 的边距矩形中放置下拉按钮而不是默认的填充矩形,我们可以指定
使用 subcontrol-position 属性更改下拉按钮在边距矩形内的对齐方式。
可以使用 width 和 height 属性来控制子控件的大小。请注意,设置 image 会隐式设置子控件的大小。
相对定位方案(position : relative),允许将子控件的定位相对于其初始位置进行偏移。例如,当按下 QComboBox 的下拉按钮时,我们可能希望内部的箭头偏移,以达到“按下”的效果。要实现这一点,我们可以指定
QComboBox::down-arrow { image: url(down_arrow.png); } QComboBox::down-arrow:pressed { position: relative; top: 1px; left: 1px; }
绝对定位方案(position : absolute)允许您改变子控件相对于参照元素的位置和尺寸。
一旦定位,它们将与小部件处理方式相同,可以使用盒模型进行样式化。
请参阅下面的子控件列表获取支持子控件列表,并查看QPushButton菜单指示子控件的自定义示例。
注意:对于像QComboBox和QScrollBar这样的复杂小部件,如果对某个属性或子控件进行了自定义,必须对其他所有属性或子控件进行自定义。
伪状态
选择器可能包含伪状态,表示根据小部件的状态限制规则的适用。伪状态位于选择器末尾,中间用冒号(:
)分隔。例如,以下规则是在鼠标悬停于QPushButton时应用。
QPushButton:hover { color: white }
可以使用感叹号运算符否定伪状态。例如,以下规则是在鼠标未悬停在QRadioButton上时应用。
QRadioButton:!hover { color: red }
伪状态可以链接,此时隐含逻辑与操作。例如,以下规则是在鼠标悬停在带有复选的QCheckBox上时应用。
QCheckBox:hover:checked { color: white }
否定伪状态可能出现在伪状态链中。例如,以下规则是在鼠标悬停在未按压的QPushButton上时应用。
QPushButton:hover:!pressed { color: blue; }
如果有必要,可以使用逗号运算符表达逻辑或。
伪状态可以与子控件一起出现。例如
QComboBox::drop-down:hover { image: url(dropdown_bright.png) }
请参阅下面的伪状态列表部分,了解Qt小部件提供的伪状态列表。
冲突解决
当几个样式规则使用不同值指定相同属性时,会出现冲突。考虑以下样式表。
QPushButton#okButton { color: gray } QPushButton { color: red }
两个规则都匹配名为okButton
的QPushButton实例,并且存在对于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,可能会让人误以为QPushButton
比QAbstractButton
更具体。然而,对于样式表计算,所有类型选择器的特定性相同,最后出现的规则具有优先级。换句话说,对于所有包括QPushButton在内的QAbstractButton,都将颜色设置为灰色
。如果我们真的希望QPushButton使用红色文本,我们总是可以重新排列规则。
Qt样式表在确定规则的特定性时遵循CSS2规范
选择器的特定性计算如下
- 计算选择器中的ID属性数量(= a)
- 计算选择器中的其他属性和伪类的数量(= b)
- 计算选择器中的元素名称数量(= c)
- 忽略伪元素[即subcontrols]
将三个数字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上、父小部件上和子小部件上。任意小部件的有效样式表是通过合并设置在数据项祖先(父代、祖父等)上的样式表以及任何设置在QApplication上的样式表获得的。
当出现冲突时,无论冲突规则的特定性如何,都始终优先选择小部件自己的样式表而不是任何继承的样式表。同样,父小部件的样式表优先于祖父的,依此类推。
这一结果的一个后果是,在数据部件上设置样式规则将自动使其优先于祖先部件样式表或在QApplication样式表中指定的其他规则。考虑以下示例。首先,我们在QApplication上设置样式表
qApp->setStyleSheet("QPushButton { color: white }");
然后我们在一个QPushButton对象上设置样式表
myPushButton->setStyleSheet("* { color: blue }");
QPushButton上的样式表强制使QPushButton(以及任何子小部件)具有蓝色文本,尽管应用范围样式表提供了更具体的规则。
如果这样写,结果将是相同的
myPushButton->setStyleSheet("color: blue");
除了如果QPushButton有子部件(这是不太可能的),样式表对此不会有影响。
样式表层叠是一个复杂的话题。有关详细信息,请参阅CSS2规范。请注意,Qt目前未实现!important
。
继承
在经典的CSS中,当一个项目的字体和颜色没有明确设置时,它们会自动从父级继承。默认情况下,当使用Qt样式表时,小部件不自动从其父小部件继承其字体和颜色设置。
例如,考虑一个QPushButton在一个QGroupBox内部
qApp->setStyleSheet("QGroupBox { color: red; } ");
QPushButton(请参阅qpushbutton.html)没有显式设置颜色。因此,它不继承其父QGroupBox(请参阅qgroupbox.html)的颜色,而是使用系统颜色。如果我们想在QGroupBox及其子对象上设置颜色,可以写出以下代码
qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");
相比之下,使用QWidget::setFont()和QWidget::setPalette()设置字体和外观,命令会传播到子控件。
如果您希望字体和外观传播到子控件,可以设置Qt::AA_UseStyleSheetPropagationInWidgetStyles标志,如下所示
使用方法
QCoreApplication::setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles, true);
当启用部件样式字体和外观传播时,通过Qt样式表做出的字体和外观更改将表现得仿佛用户已手动调用相应QWidget::setPalette()和QWidget::setFont()方法对所有由样式表指定的QWidgets进行操作。
- 样式表做出的更改会传播。它们在更改发生时, будут推送到一次匹配样式表的全部控件。
- 调用QWidget::setPalette()或QWidget::setFont()做出的更改会被继承。它们被所有现有和未来的子控件继承,前提是相应的画笔或字体没有显式设置。
C++命名空间内的控件
类型选择器可用于为特定类型的控件设置样式。例如,
class MyPushButton : public QPushButton { // ... } // ... qApp->setStyleSheet("MyPushButton { background: yellow; }");
Qt样式表使用QObject::className()来确定何时应用类型选择器。当自定义控件在命名空间内时,QObject::className()返回<namespace>::<classname>。这与子控件语法的语法冲突。为了克服这个问题,当在命名空间内的控件上使用类型选择器时,我们必须将::
替换为--
。例如,
namespace ns { class MyPushButton : public QPushButton { // ... } } // ... 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语法,因为它会修改正在绘制的控件。此外,qproperty语法的评估仅进行一次,这发生在控件被样式美化时。这意味着任何在伪状态(如QPushButton:hover)中尝试使用它们的尝试都不会起作用。
© 2024 Qt公司有限公司。本文件中包含的文档贡献由各自的版权方拥有。本文件提供的文档是根据自由软件基金会发布的GNU自由文档许可版本1.3条款许可的。Qt和相关的标志是芬兰以及在世界其他地区的Qt公司有限公司的商标。所有其他商标均为其各自拥有者的财产。