从零开始学Qt(20)QSS详解(2)QSS语法
QSS的术语和语法规则几乎与HTMLCSS相同。如果你已经了解CSS,可以快速浏览本文。样式规则
样式表由一系列样式规则组成。样式规则由选择器(selector)和声明(declaration)组成。选择器指定哪些widgets受规则影响;声明指定应在widget上设置哪些属性。例如:QPushButton{color:red}
在上面的样式规则中,QPushButton是选择器,{color:red}是声明。该规则指定QPushButton及其子类(例如MyPushButton)使用红色作为其前景色。
QSS通常不区分大小写(即color,Color,COLOR和cOloR表示相同的属性)。唯一的例外是类名、对象名和Qt属性名,它们区分大小写。
可以为同一声明指定多个选择器,使用逗号分隔选择器。例如,规则QPushButton,QLineEdit,QComboBox{color:red}
等效于以下三个规则序列:QPushButton{color:red}QLineEdit{color:red}QComboBox{color:red}
样式规则的声明部分是值对的列表,括在大括号中并用分号分隔。例如
QPushButton{color:red;backgroundcolor:white}选择器类型
到目前为止,所有示例都使用了最简单的选择器类型,即类型选择器。QSS支持CSS2中定义的所有选择器。下表总结了最有用的选择器类型。
辅助控制器(subcontrol)
要设置复杂widgets的样式,必须利用widget的辅助控制器(相当于子控件),例如QComboBox的下拉按钮或QSpinBox的上下箭头。选择器可能包含特定的辅助控制器,以便限制规则的应用。例如:QComboBox::dropdown{image:url(dropdown。png)}
上述规则设置了所有QComboBox的下拉按钮的样式。虽然双冒号(::)语法让人想起CSS3的伪元素,Qt辅助控制器在概念上与这些不同,并且具有不同的级联语义。
辅助控制器始终相对于另一个元素(参考元素)声明。此参考元素可以是widget或是其他辅助控制器。
可以使用subcontrolorigin属性更改要使用的源矩形。例如,如果我们想将下拉列表放在QComboBox的边距矩形(marginrectangle)而不是默认的填充矩形(Paddingrectangle)中,我们可以指定:QComboBox{marginright:20px;}QComboBox::dropdown{subcontrolorigin:margin;}
边距矩形内下拉列表的对齐方式使用subcontrolposition属性进行更改。
width和height属性可用于控制子控件的大小。请注意,设置图像会隐式地设置子控件的大小。
相对位置(position:relative),允许子控件的位置偏离其初始位置。例如,当按下QComboBox的下拉按钮时,我们可能希望内部箭头偏移以产生按下效果。为此,我们可以指定:QComboBox::downarrow{image:url(downarrow。png);}QComboBox::downarrow:pressed{position:relative;top:1px;left:1px;}
绝对位置(position:absolute),允许相对于参考元素更改子控件的位置和大小。
定位后,它们被视为与widget相同,并且可以使用框模型(boxmodel)设置样式。
注意:对于复杂的widget(如QComboBox和QScrollBar),如果自定义了一个属性或子控件,则还必须自定义所有其他属性或子控件。伪态(PseudoStates)
选择器可以包含伪态,表示根据widget的状态限制规则的应用。伪态出现在选择器的末尾,用冒号分隔。例如,当鼠标悬停在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::dropdown:hover{image:url(dropdownbright。png)}冲突解决
当多个样式规则指定具有不同值的相同属性时,就会发生冲突。请考虑以下样式表:QPushButtonokButton{color:gray}QPushButton{color:red}
这两个规则都匹配名为okButton的QPushButton实例,并且color属性存在冲突。为了解决这种冲突,我们必须考虑选择器的特异性(specificity)。在上面的例子中,QPushButtonokButton被认为比QPushButton更具体,因为它(通常)引用单个对象,而不是类的所有实例。
同样,具有伪态的选择器比不指定伪态的选择器更具体。因此,以下样式表指定当鼠标悬停在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),并且color属性存在冲突。由于QPushButton继承了QAbstractButton,因此很容易假设QPushButton比QAbstractButton更具体。但是对于样式表,所有类型选择器都具有相同的特异性,规则为最后出现的优先。换句话说,所有QAbstractButtons(包括QPushButtons)的颜色都设置为灰色。如果我们真的希望QPushButton有红色文本,我们可以随时对规则重新排序。
为了确定规则的特异性,QSS遵循CSS2的规范。
选择器的特异性计算如下:计算选择器中ID属性的数量(a)计算选择器中其他属性和伪类(pseudoclasses)的数量(b)计算选择器中的元素名称数(c)忽略伪元素〔即subcontrols〕。三个数字运算abc给出特异性。
一些例子:{}a0b0c0specificity0LI{}a0b0c1specificity1ULLI{}a0b0c2specificity2ULOLLI{}a0b0c3specificity3H1〔RELup〕{}a0b1c1specificity11ULOLLI。red{}a0b1c3specificity13LI。red。level{}a0b2c1specificity21x34y{}a1b0c0specificity100级联(Cascading)
样式表可以在QApplication、父控件和子控件上设置。任意widget的有效样式表是通过合并widget的所有父控件上的样式表以及QApplication上的任何样式表来获得的。
当发生冲突时,无论冲突规则的特异性如何,widget自己的样式表始终优先于任何继承的样式表。同样,父控件的样式表优先于祖控件的样式表等。
这样做的一个结果是,在widget上设置样式规则会自动使其优先于祖控件的样式表或QApplication样式表中指定的其他规则。请考虑以下示例。首先,我们在QApplication上设置一个样式表:qAppsetStyleSheet(QPushButton{color:white});
然后我们在QPushButton对象上设置一个样式表:myPushButtonsetStyleSheet({color:blue});
QPushButton上的样式表强制QPushButton(和任何子控件)具有蓝色文本,尽管应用程序范围内的样式表提供了更具体的规则集。
以下方式结果也是相同,myPushButtonsetStyleSheet(color:blue);
除非QPushButton有子项(这不太可能),样式表对它们没有影响。继承
在经典CSS中,当项目的字体和颜色未显式设置时,它会自动从父项继承。默认情况下,使用Qt样式表时,widget不会自动从其父控件继承其字体和颜色设置。
例如,考虑QGroupBox中的QPushButton:qAppsetStyleSheet(QGroupBox{color:red;});
QPushButton没有显式地设置颜色。因此,它不继承其父控件QGroupBox的颜色,而是具有系统颜色。如果我们想在QGroupBox及其子项上设置颜色,我们可以这样写:qAppsetStyleSheet(QGroupBox,QGroupBox{color:red;});
相反,使用QWidget::setFont()和QWidget::setPalette()设置字体和调色板会传到子控件。
如果你希望字体和调色板继承到子控件,则可以设置Qt::AAUseStyleSheetPropagationInWidgetStyles标志,如下所示:QCoreApplication::setAttribute(Qt::AAUseStyleSheetPropagationInWidgetStyles,true);C命名空间中的widget
类型选择器可用于设置特定类型的widget的样式。例如classMyPushButton:publicQPushButton{。。。}。。。qAppsetStyleSheet(MyPushButton{background:yellow;});
QSS使用widget的QObject::className()来确定何时应用类型选择器。当自定义widget位于命名空间内时,QObject::className()返回::。这与辅助控制器的语法冲突。为了克服这个问题,当对命名空间中的widget使用类型选择器时,我们必须将::替换为。例如namespacens{classMyPushButton:publicQPushButton{。。。}}。。。qAppsetStyleSheet(nsMyPushButton{background:yellow;});设置QObject属性
从4。3及更高版本开始,任何可设计的QPROPERTY都可以使用qproperty属性名称语法进行设置。例如MyLabel{qpropertypixmap:url(pixmap。png);}MyGroupBox{qpropertytitleColor:rgb(100,200,100);}QPushButton{qpropertyiconSize:20px20px;}
如果属性引用QENUMS声明的枚举,则应按名称引用而不是它们的数值。
注:请谨慎使用qproperty语法,因为它会修改正在绘制的widget。此外,qproperty语法只应用一次,即widget被样式润色时。这意味着不能在任何伪态(如QPushButton:hover)中使用它们。