Qt入门系列开发教程【QSS】QSS选择器
描述
Qt样式表术语和语法规则几乎与HTML CSS相同。如果你已经了解CSS,你可以快速浏览这一部分。
规则
样式表由一系列样式规则组成。样式规则由选择器和声明组成。选择器指定哪些小部件受规则影响;声明指定应该在小部件上设置哪些属性。例如:
QPushButton { color: red }
在上面的样式规则中,QPushButton是选择器,{color:red}是声明。该规则规定QPushButton及其子类(例如MyButton)应使用红色作为前景色。
Qt样式表通常不区分大小写(即,color、color、color和color指的是同一属性)。唯一的例外是类名、对象名和Qt属性名,它们区分大小写。
可以为同一声明指定多个选择器,使用逗号(,)分隔选择器。例如,规则
QPushButton, QLineEdit, QComboBox { color: red }
相当于这三条规则的顺序:
QPushButton { color: red }
QLineEdit { color: red }
QComboBox { color: red }
样式规则的声明部分是属性:值对的列表,用大括号({})括起来,用分号分隔。例如:
QPushButton { color: red; background-color: white }
选择器
选择器 | eg | 选择内容 |
---|---|---|
通用选择器 | * | 所有widget |
类型选择器 | QPushButton | 匹配QPushButton及其子类的实例 |
属性选择器 | QPushButton[flat=“false”] | 匹配QPushButton的非flat实例。 可以使用此选择器测试支持QVariant::toString()的任何Qt属性 此外,还支持特殊类属性作为类的名称。 此选择器也可用于测试动态特性。 |
类选择器 | .QPushButton | 匹配QPushButton的实例,但不匹配其子类。这相当于*[class~=“QPushButton”]。 |
id选择器 | QPushButton#okButton | 匹配对象名为okButton的所有QPushButton实例。 |
后代选择器 | QDialog QPushButton | 匹配QPushButton的所有实例,这些实例是QDialog的子代(子代、孙辈等)。 |
子选择器 | QDialog > QPushButton | 匹配QPushButton的所有实例,这些实例是QDialog的直接子对象。 |
子控件
对于复杂小部件的样式,有必要访问小部件的子控件,例如QComboBox的下拉按钮或QSpinBox的上下箭头。选择器可能包含子控件,从而可以将规则的应用限制到特定的小部件子控件。例如:
QComboBox::drop-down { image: url(dropdown.png) }
以上规则为所有QComboBox的下拉按钮设置样式。虽然双冒号(::)语法让人想起CSS3伪元素,但Qt子控件在概念上与这些控件不同,并且具有不同的级联语义。
子控件始终相对于另一个元素(参考元素)进行定位。这个引用元素可以是小部件或另一个子控件。例如,默认情况下,QCOMBOX的::下拉列表位于QCOMBOX填充矩形的右上角。默认情况下,::下拉列表位于::下拉子控件的内容矩形的中心。请参阅下面的可设置样式的小部件列表,了解用于设置小部件样式及其默认位置的子控件。
可以使用Subcrol origin属性更改要使用的原点矩形。例如,如果要将下拉列表放置在QComboBox的边距矩形中,而不是默认的填充矩形中,则可以指定:
QComboBox::down-arrow {
image: url(down_arrow.png);
}
QComboBox::down-arrow:pressed {
position: relative;
top: 1px; left: 1px;
}
绝对定位方案(位置:绝对)允许改变子控件相对于参考元素的位置和大小。
定位后,它们被视为小部件,可以使用box模型进行样式设置。
伪态
选择器可能包含伪状态,表示根据小部件的状态限制规则的应用。伪状态出现在选择器的末尾,中间有一个冒号(:)。例如,当鼠标悬停在QPushButton上时,以下规则适用:
QPushButton:hover { color: white }
伪状态可以使用感叹号运算符求反。例如,当鼠标未悬停在QRadioButton上时,以下规则适用:
QRadioButton:!hover { color: red }
伪状态可以被链接,在这种情况下,逻辑和是隐含的。例如,当鼠标悬停在选中的QCheckBox上时,以下规则适用:
QCheckBox:hover:checked { color: white }
否定伪态可能出现在伪态链中。例如,当鼠标悬停在未按下的QPushButton上时,以下规则适用:
QPushButton:hover:!pressed { color: blue; }
如果需要,可以使用逗号运算符表示逻辑或:
QCheckBox:hover, QCheckBox:checked { color: white }
伪状态可以与子控件一起出现。例如:
QComboBox::drop-down:hover { image: url(dropdown_bright.png) }
冲突样式
当多个样式规则使用不同的值指定相同的特性时,会发生冲突。考虑下面的样式表:
QPushButton#okButton { color: gray }
QPushButton { color: red }
这两个规则都匹配名为okButton的QPushButton实例,并且颜色属性存在冲突。要解决这一冲突,我们必须考虑选择者的特殊性。在上面的示例中,QPushButton#okButton被认为比QPushButton更具体,因为它(通常)指的是单个对象,而不是一个类的所有实例。
类似地,具有伪状态的选择器比不指定伪状态的选择器更具体。因此,以下样式表指定,当鼠标悬停在QPushButton上时,QPushButton应具有白色文本,否则为红色文本:
QPushButton:hover { color: white }
QPushButton { color: red }
QPushButton:hover:enabled { color: white }
QPushButton:enabled { color: red }
QPushButton { color: red }
QAbstractButton { color: gray }
这两个规则都适用于QPushButton实例(因为QPushButton继承了QAbstractButton),并且颜色属性存在冲突。因为QPushButton继承了QAbstractButton,所以可能会有人认为QPushButton比QAbstractButton更具体。然而,对于样式表计算,所有类型选择器都具有相同的特性,最后出现的规则优先。换句话说,所有QAbstractButtons(包括QPushButtons)的颜色都设置为灰色。如果我们真的希望QPushButtons有红色文本,我们总是可以重新排列规则。
选择器的特异性计算如下:
- 计算选择器中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、父窗口小部件和子窗口小部件上设置样式表。任意小部件的有效样式表是通过合并小部件的祖先(父母、祖父母等)上的样式表集以及QApplication上的任何样式表集获得的。
当出现冲突时,无论冲突规则的特殊性如何,小部件自己的样式表总是优先于任何继承的样式表。同样,父窗口小部件的样式表比祖父母的样式表更受欢迎,等等。
这样做的一个结果是,在小部件上设置样式规则会自动使其优先于在祖先小部件的样式表或QApplication样式表中指定的其他规则。考虑下面的例子。首先,我们在QApplication上设置了一个样式表:
qApp->setStyleSheet("QPushButton { color: white }");
然后我们在QPushButton对象上设置样式表:
myPushButton->setStyleSheet("* { color: blue }");
QPushButton上的样式表强制QPushButton(以及任何子小部件)具有蓝色文本,尽管应用程序范围的样式表提供了更具体的规则集。
如果我们写的话,结果会是一样的
继承
在经典CSS中,当一个项目的字体和颜色没有明确设置时,它会自动从父项继承。默认情况下,当使用Qt样式表时,小部件不会自动从其父小部件继承其字体和颜色设置。
FQPushButton 包含在一个 QGroupBox:
qApp->setStyleSheet("QGroupBox { color: red; } ");
QPushButton没有明确的颜色集。因此,它没有继承其父QGroupBox的颜色,而是具有系统颜色。如果我们想设置QGroupBox及其子项的颜色,我们可以写:
qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");
相比之下,使用QWidget::setFont()和QWidget::setPalette()设置字体和调色板会传播到子小部件。
如果希望字体和调色板传播到子窗口小部件,可以设置Qt::AA_UseStyleSheetPropagationWidgetStyles标志,如下所示:
QCoreApplication::setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles, true);
启用小部件样式字体和调色板传播后,通过Qt样式表进行的字体和调色板更改将表现为用户在样式表所针对的所有QWidget上手动调用了相应的QWidget::setPalette()和QWidget::setFont()方法。如果这会导致C++中的传播,它将导致样式表中的传播,反之亦然。
C++命名空间内部的widget
类型选择器可用于为特定类型的小部件设置样式。例如
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_属性。
MyLabel { qproperty-pixmap: url(pixmap.png); }
MyGroupBox { qproperty-titleColor: rgb(100, 200, 100); }
QPushButton { qproperty-iconSize: 20px 20px; }
- 点赞
- 收藏
- 关注作者
评论(0)