样式表句法

Qt 样式表术语和语法规则,几乎等同 HTML CSS。若已经了解 CSS,就可以快速略读本章节。

样式规则

样式表由一系列样式规则组成。 样式规则 由选择器和声明组成。 选择器 指定受规则影响的 Widget; 声明 指定应该为 Widget 设置哪些特性。例如:

QPushButton { color: red }
					

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

Qt 样式表一般不区分大小写 (即 color , Color , COLOR ,和 cOloR 引用相同特性)。唯一例外是类、 对象名称 、及 Qt 特性名称,它们要区分大小写。

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

QPushButton, QLineEdit, QComboBox { color: red }
					

相当于这 3 条规则序列:

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

样式规则的声明部分是列表化的 property: value 对,封闭于花括号 ( {} ) 并采用 ; 分号分隔。例如:

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

特性列表 下文章节,了解由 Qt Widgets 提供的特性列表。

选择器类型

到目前为止,所有范例均使用最简单选择器类型 (类型选择器)。Qt 样式表支持所有 由 CSS2 定义的选择器 。下表汇总了最有用的选择器类型。

选择器 范例 解释
通用选择器 * 匹配所有 Widget。
类型选择器 QPushButton 匹配实例化的 QPushButton 及其子类。
特性选择器 QPushButton[flat="false"] 匹配实例化的 QPushButton that are not flat . You may use this selector to test for any Qt property 支持 QVariant::toString () (见 toString() function documentation for details). In addition, the special class property is supported, for the name of the class.

This selector may also be used to test dynamic properties. For more information on customization using dynamic properties, refer to 定制使用动态特性 .

Instead of = ,还可以使用 ~= to test whether a Qt property of type QStringList 包含给定 QString .

警告: If the value of the Qt property changes after the style sheet has been set, it might be necessary to force a style sheet recomputation. One way to achieve this is to unset the style sheet and set it again.

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

这相当于 *[class~="QPushButton"] .

ID 选择器 QPushButton#okButton 匹配所有 QPushButton instances whose 对象名称 is okButton .
后代选择器 QDialog QPushButton 匹配所有实例化的 QPushButton that are descendants (children, grandchildren, etc.) of a QDialog .
子级选择器 QDialog > QPushButton 匹配所有实例化的 QPushButton that are direct children of a QDialog .

子控件

For styling complex widgets, it is necessary to access subcontrols of the widget, such as the drop-down button of a QComboBox or the up and down arrows of a QSpinBox 。选择器可能包含 subcontrols that make it possible to restrict the application of a rule to specific widget subcontrols. For example:

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

The above rule styles the drop-down button of all QComboBox es. Although the double-colon ( :: ) syntax is reminiscent of CSS3 Pseudo-Elements, Qt Sub-Controls differ conceptually from these and have different cascading semantics.

Sub-controls are always positioned with respect to another element - a reference element. This reference element could be the widget or another Sub-control. For example, the ::drop-down QComboBox is placed, by default, in the top right corner of the Padding rectangle of the QComboBox ::drop-down is placed, by default, in the Center of the Contents rectangle of the ::drop-down 子控件。见 可样式化 Widget 列表 below for the Sub-controls to use to style a widget and their default positions.

The origin rectangle to be used can be changed using the subcontrol-origin property. For example, if we want to place the drop-down in the margin rectangle of the QComboBox instead of the default Padding rectangle, we can specify:

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

The alignment of the drop-down within the Margin rectangle is changed using subcontrol-position 特性。

width and height properties can be used to control the size of the Sub-control. Note that setting a image implicitly sets the size of a Sub-control.

The relative positioning scheme ( position : relative), allows the position of the Sub-Control to be offset from its initial position. For example, when the QComboBox 's drop-down button is pressed, we might like the arrow inside to be offset to give a "pressed" effect. To achieve this, we can specify:

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

绝对位置方案 ( position : absolute), allows the position and size of the Sub-control to be changed with respect to the reference element.

Once positioned, they are treated the same as widgets and can be styled using the Box 模型 .

子控件列表 下文了解支持的子控件列表,和 定制 QPushButton 的菜单指示器子控件 了解现实范例。

注意: 采用复杂 Widget,譬如 QComboBox and QScrollBar , if one property or sub-control is customized, all the other properties or sub-controls must be customized as well.

伪状态

选择器可以包含 伪状态 that denote that restrict the application of the rule based on the widget's state. Pseudo-states appear at the end of the selector, with a colon ( : ) in between. For example, the following rule applies when the mouse hovers over a QPushButton :

QPushButton:hover { color: white }
					

Pseudo-states can be negated using the exclamation operator. For example, the following rule applies when the mouse does not hover over a QRadioButton :

QRadioButton:!hover { color: red }
					

Pseudo-states can be chained, in which case a logical AND is implied. For example, the following rule applies to when the mouse hovers over a checked QCheckBox :

QCheckBox:hover:checked { color: white }
					

Negated Pseudo-states may appear in Pseudo-state chains. For example, the following rule applies when the mouse hovers over a QPushButton that is not pressed:

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

If needed, logical OR can be expressed using the comma operator:

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

Pseudo-states can appear in combination with subcontrols. For example:

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

伪状态列表 section below for the list of pseudo-states provided by Qt widgets.

解决冲突

Conflicts arise when several style rules specify the same properties with different values. Consider the following style sheet:

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

两者规则匹配 QPushButton 实例称为 okButton and there is a conflict for the color property. To resolve this conflict, we must take into account the specificity of the selectors. In the above example, QPushButton#okButton is considered more specific than QPushButton , because it (usually) refers to a single object, not to all instances of a class.

Similarly, selectors with pseudo-states are more specific than ones that do not specify pseudo-states. Thus, the following style sheet specifies that a QPushButton should have white text when the mouse is hovering over it, otherwise red text:

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

Here's a tricky one:

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

Here, both selectors have the same specificity, so if the mouse hovers over the button while it is enabled, the second rule takes precedence. If we want the text to be white in that case, we can reorder the rules like this:

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

Alternatively, we can make the first rule more specific:

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

A similar issue arises in conjunction with Type Selectors. Consider the following example:

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

Both rules apply to QPushButton 实例 (由于 QPushButton 继承 QAbstractButton ) and there is a conflict for the color 特性。因为 QPushButton 继承 QAbstractButton , it might be tempting to assume that QPushButton is more specific than QAbstractButton . However, for style sheet computations, all Type Selectors have the same specificity, and the rule that appears last takes precedence. In other words, color 被设为 gray for all QAbstractButton s, including QPushButton s. If we really want QPushButton s to have red text, we can always reorder the rules.

为确定规则的特异性,Qt 样式表遵循 CSS2 规范 :

A selector's specificity is calculated as follows:

  • count the number of ID attributes in the selector (= a)
  • count the number of other attributes and pseudo-classes in the selector (= b)
  • count the number of element names in the selector (= c)
  • ignore pseudo-elements [i.e., subcontrols ].

Concatenating the three numbers a-b-c (in a number system with a large base) gives the specificity.

一些范例:

*             {}  /* 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 , on parent widgets, and on child widgets. An arbitrary widget's effective style sheet is obtained by merging the style sheets set on the widget's ancestors (parent, grandparent, etc.), as well as any style sheet set on the QApplication .

When conflicts arise, the widget's own style sheet is always preferred to any inherited style sheet, irrespective of the specificity of the conflicting rules. Likewise, the parent widget's style sheet is preferred to the grandparent's, etc.

One consequence of this is that setting a style rule on a widget automatically gives it precedence over other rules specified in the ancestor widgets' style sheets or the QApplication style sheet. Consider the following example. First, we set a style sheet on the QApplication :

qApp->setStyleSheet("QPushButton { color: white }");
					

Then we set a style sheet on a QPushButton 对象:

myPushButton->setStyleSheet("* { color: blue }");
					

样式表在 QPushButton 强制 QPushButton (and any child widget) to have blue text, in spite of the more specific rule set provided by the application-wide style sheet.

The result would have been the same if we had written

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

except that if the QPushButton had children (which is unlikely), the style sheet would have no impact on them.

Style sheet cascading is a complex topic. Refer to the CSS2 规范 for the gory details. Be aware that Qt currently doesn't implement !important .

继承

In classic CSS, when font and color of an item is not explicitly set, it gets automatically inherited from the parent. By default, when using Qt Style Sheets, a widget does not automatically inherit its font and color setting from its parent widget.

例如,认为 QPushButton QGroupBox :

qApp->setStyleSheet("QGroupBox { color: red; } ");
					

QPushButton does not have an explicit color set. Hence, instead of inheriting color of its parent QGroupBox , it has the system color. If we want to set the color on a QGroupBox and its children, we can write:

qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");
					

In contrast, setting a font and palette using QWidget::setFont () 和 QWidget::setPalette () propagates to child widgets.

If you would prefer that the font and palette propagate to child widgets, you can set the Qt::AA_UseStyleSheetPropagationInWidgetStyles 标志,像这样:

用法:

QCoreApplication::setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles, true);
					

When the widget-style font and palette propagation is enabled, font and palette changes made through Qt Style Sheets will behave as though the user had manually called the corresponding QWidget::setPalette () 和 QWidget::setFont () methods on all of the QWidgets targeted by the style sheet. If this would have caused propagation in C++, it will cause propagation in style sheets and vice versa.

在 C++ 名称空间中的 Widget

The Type Selector can be used to style widgets of a particular type. For example,

class MyPushButton : public QPushButton {
    // ...
}
// ...
qApp->setStyleSheet("MyPushButton { background: yellow; }");
					

Qt Style Sheet uses QObject::className() of the widget to determine when to apply the Type Selector. When custom widgets are inside namespaces, the QObject::className() returns <namespace> :: <classname>. This conflicts with the syntax for 子控件 . To overcome this problem, when using the Type Selector for widgets inside namespaces, we must replace the " :: " with "--". For example,

namespace ns {
    class MyPushButton : public QPushButton {
        // ...
    }
}
// ...
qApp->setStyleSheet("ns--MyPushButton { background: yellow; }");
					

设置 QObject 特性

从 4.3 及以上,任何可设计 Q_PROPERTY can be set using the qproperty-<property name> syntax.

例如,

MyLabel { qproperty-pixmap: url(pixmap.png); }
MyGroupBox { qproperty-titleColor: rgb(100, 200, 100); }
QPushButton { qproperty-iconSize: 20px 20px; }
					

If the property references an enum declared with Q_ENUMS, you should reference its constants by name, i.e., not their numeric value.

注意: Use the qproperty syntax with care, as it modifies the widget that is being painted. Also, the qproperty syntax is evaluated only once, which is when the widget is polished by the style. This means that any attempt to use them in pseudo-states such as QPushButton :hover,将不工作。