Qt之stylesheet使用介绍

Qss的术语和语法几乎和HTML CSS相同,如果你已经熟悉CSS,你可以快速的浏览本文。

样式规则

  样式表由一系列的样式规则组成。一条样式规则由一个选择器和一个声明语句组成,选择器指明了哪个(或者说是哪种)部件将会受规则影响,而声明语句则指明了哪些属性会设置到这个(这些)部件.

举个例子:

QPushButton {color: red}
  • 1

  在上面的样式规则中,QPushBbutton就是选择器,而{ color: red}则是声明语句。该规则指明了QPushButton和它的子类(如:MyPushButton)应该使用红色作为它们的前景色。Qt样式表通常是不区分大小写的(比如:color, Color, COLOR, 和 cOloR 都是表示同一个属性)。当然也有区分大小写的,类名、对象名、Qt属性名(与color这些属性不是一回事,后面详细解释)这几个都是需要区分大小写的。

  几个选择器可以指定同样的声明语句,使用(,)来隔开不同的选择器,举个例子,如下规则:

QPushButton, QLineEdit, QComboBox { color: red }
  • 1

  与下面三个规则是等价的:

QPushButton { color: red }
QLineEdit { color: red }
QComboBox { color: red }
  • 1
  • 2
  • 3

  样式规则的声明语句部分是一个属性:值对列表,由({})包闭,由分号作为分割,举个例子:

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

  查看更多由Qt widgets提供的属性列表(属性名大概看一下就知道什么意思了,有时间再详细说吧)

选择器类型

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

选择器 实例 描述
通用选择器 * 匹配所有的widget
类型选择器 QPushButton 匹配所有的QPushButton实例和继承于它的子类
属性选择器 QPushButton[flat=”false”] 匹配所有非flat的QPushButton(通常情况下,使用Q_PROPERTY宏来声明你的属性,比如此例中的flat),并且要注意,你的属性类型要受 QVariant::toString()支持(查看toString()方法的帮助文档以获取更详细的解释).
这个选择器类型也可以用来判断动态属性,要了解更多使用自定义动态属性的细节,请参考使用自定义动态属性 。
除了使用=,你还可以使用~=来判断一个QStringList中是否包含给定的QString。
警告:如果在设置了样式表后,相应的属性值发生了改变(如:flat变成了”true”),则有必要重新加载样式表,一个有效的方法是,取消样式表,再重新设置一次,下面的代码是其中一种方式:

style()->unpolish(this);
style()->polish(this);// force a stylesheet recomputation
类选择器 .QPushButton 匹配所有的QPushButton实例,但不包括它的子类,与*[class~=”QPushButton”]是等价的。
ID选择器 QPushButton#okButton 匹配所有object name为”okButton”的QPushButton实例。
后裔选择器 QDialog QPushButton 匹配所有继承于QDialog(包括其所有子孙)的QPushButton实例。
子选择器 QDialog > QPushButton 匹配所有直接继承与QDialog的QPushButton实例。

Sub-Controls

  为了样式化你的复杂widget,很有必要使用widget的subcontrol,比如QComboBox的drop-down 部分或者是QSpinBox的上和下箭头。选择器也许会包含subcontrols用于限制widget的subcontrols,举个例子:

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

  上述规则样式化所有QComboBox的drop-down部分,虽然双冒号(::)让人联想到CSS3的伪元素语法,但是Qt的 Sub-Controls 跟它是不一样的。

  Sub-Controls始终相对于另一个元素来定位–一个参考元素。这个参考元素可以是一个Widget又或者是另一个Sub-Control。举个例子,QComboBox的::drop-down默认被放置于QComboBox的Padding rectangle(盒子模型)的右上角。::drop-down默认会被放置于另一个::drop-down Sub-Control的中心。查看可样式化的Widget列表以了解更多使用Sub-Control来样式化Widget和初始化其位置的内容。

  源rectangle可以使用subcontrol-origin来改变。举个例子,如果我们想要把drop-down放置于QComboBox的margin rectangle而不是默认的Padding rectangle,我们可以像下面这样指定:

QComboBox {
    margin-right: 20px;
}
QComboBox::drop-down {
    subcontrol-origin: margin;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

  drop-down在Margin rectangle内的排列方式可以由subcontrol-position来改变. 
  width和height属性可以用来控制Sub-control的size.需要注意的是,设置了image就隐式的设置了Sub-control的size了。

  相对定位方案(position:relative),允许Sub-Control的位置从它的初始化位置作出偏移。举个例子,当QComboBox的drop-down按钮被pressed时,我们也许想要那个箭头作出位移以显示一种“pressed”的效果,为了达到目标,我们可以像下面那样指定:

QComboBox::down-arrow {
    image: url(down_arrow.png);
}
QComboBox::down-arrow:pressed {
    position: relative;
    top: 1px; left: 1px;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

  绝对定位方案(position : absolute),使得Sub-control的position和size基于其参考元素而改变。

  一旦定位,它们将会与widget同等对待并且可以使用盒子模型来样式化。

  查看Sub-Control列表以了解那些sub-control是被支持的,并且可以查看自定义QPushButton的菜单指示器Sub-Control来了解一个实际的使用例子。

  注意:像QComboBox和QScrollBar这样的复杂部件,如果sub-control的一项属性是自定义的,那么其他所有的属性跟sub-control也都应该自定义。

伪状态

  选择器也许会包含基于widget的state的程序限制规则的伪状态。伪状态以冒号(:)作为分隔紧跟着选择器。举个例子,下面的规则在鼠标悬浮在QPushButton的上方时生效:

QPushButton:hover { color: white }
  • 1

  伪状态可以使用感叹号进行取反,下面一条规则在鼠标没有悬浮在QRadioButton上方时生效:

QRadioButton:!hover { color: red }
  • 1

  伪状态可以链接,在这样的情况下,隐式地包含了逻辑与。举个例子,下面一条规则在鼠标悬浮到一个已check的QCheckBox上时生效:

QCheckBox:hover:checked { color: white }
  • 1

  伪状态的取反也可以出现在伪状态链中,举个例子,下面的规则在鼠标悬浮到一个没有被press的QPushButton上时生效:

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

  如果有需要,可以使用逗号来表示逻辑或:

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

  伪状态可以与subcontrol组合使用,举个例子:

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

查看由Qt widgets提供的伪状态列表章节

解决冲突

  当几个样式规则为同一个属性指定不同的值时,就产生了冲突。请考虑下面的样式表:

QPushButton#okButton { color: gray }
QPushButton { color: red }
  • 1
  • 2

  两条规则都匹配名为okButton的QPushButton实例并且冲突于颜色属性。为了解决冲突,我们必须考虑到选择器的特殊性。在上面的例子中,QPushButton#okButton被视为比QPushButton更特殊,因为它(通常)指向一个单一的对象而不是QPushButton的所有实例。

  相似的,指定了伪状态的选择器比没有指定伪状态的更特殊。从而,下面的样式表指明了当鼠标悬浮到QPushButton上方时其字体颜色应该为白色,而其余情况则为红色:

QPushButton:hover { color: white }
QPushButton { color: red }
  • 1
  • 2

  接下来看一个很有意思的:

QPushButton:hover { color: white }
QPushButton:enabled { color: red }
  • 1
  • 2

  两个选择器都有相同的特殊性,所以当鼠标悬浮在一个enabled的按钮上时,第二条规则优先。如果在这种情况下我们想要文字变成白色,我们可以像下面那样重新排布一下样式规则:

QPushButton:enabled { color: red }
QPushButton:hover { color: white }
  • 1
  • 2

  另外,我们可以使第一条规则更特殊一些:

QPushButton:hover:enabled { color: white }
QPushButton:enabled { color: red }
  • 1
  • 2

  相似的问题出现在相互配合的类型选择器上。考虑以下情况:

QPushButton { color: red }
QAbstractButton { color: gray }
  • 1
  • 2

  两条规则都应用于QPushButton的实例(因为QPushButton继承于QAbstractButton)并且冲突于color属性。因为QPushButton继承于QAbstractButton,这让人不禁想到QPushButton比QAbstractButton更特殊。然而,对于样式表的运算,所有的类型选择器都具有同等的特殊性,并且出现在更后面的规则优先级更高。换句话说,QAbstractButton的color会被设置成灰色,包括QPushButton。如果我们确实想要QPushButton字体颜色设置为红色,我们总是可以使用重新排列样式表规则顺序的方式实现。

为确定规则的特殊性,Qt样式表跟随CSS2规范

一个选择器的特殊性由下面的方式计算: 
- 计算选择器中ID属性的数量[=a] 
- 计算选择器中其他属性和伪类的数量[=b] 
- 计算选择器中元素名字的数量[=c] 
- 忽略伪原素[如:subcontrol]

串联这三个数字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 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

级联

  样式表可以设置到QApplication、父部件、子部件。任意部件应用的样式表通过合并设置到祖先部件(父亲、祖父等)的样式表获得,以及设置到QApplication上的任何样式表。

  当冲突产生时,部件本身的样式表总是优先于继承来的样式表,不论冲突规则计算的特殊性是多少。同样,父部件的样式表优先级要高于祖父部件的等等。

  这样做的一个后果是,部件上的一个样式规则自动获得高于其他由祖先部件或QApplication样式表指定的样式规则。考虑下面这个例子。首先,我们给QApplication设置样式表:

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

  然后,我们给一个QPushButton对象设置样式表:

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

  设置到QPushButton上的样式表强制要求QPushButton(包括其任何子部件)的字体颜色为蓝色,尽管程序范围内的样式表给出了更详尽的样式规则。

  如果我们写成下面这样,效果还是一样的:

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

  如果该QPushButton有孩子(这是不太可能的),这段样式表对它们无效。

  样式表级联是一个很复杂的话题。请参考CSS2规范获取更多细节。请注意Qt目前没有实现的!很重要。

继承

  在典型的CSS中,如果一个项的字体和颜色没有显式设置,它会自动从其父亲获得。当使用Qt样式表时,一个部件不会从其父亲继承字体和颜色的设置(请注意,父亲和父类、孩子和子类都是不同的概念,不要搞混)。

举个例子,考虑一个QGroupBox内有一个QPushButton:

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

  QPushButton没有任何显式的color设置。因此,它会获得系统的颜色而不是从父亲继承color的值。如果我们要设置QGroupBox及其所有孩子的color,我们可以这样写:

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

  与此相反,使用QWidget::setFont()可以设置字体包括孩子的字体,使用 QWidget::setPalette()可以设置调色板包括孩子的调色板。

C++命名空间内的部件

类型选择器可以用于样式化特定的类型,举个例子:

class MyPushButton : public QPushButton {
    // ...
}

// ...
qApp->setStyleSheet("MyPushButton { background: yellow; }");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

  Qt样式表使用widget的QObject::className()来决定何时应用类型选择器。当自定义部件在命名空间之中,QObject::className()会返回::。这与subcontrol产生了冲突。为了解决这个问题,当为命名空间中widget使用类型选择器时,我们必须将”::”替换成”–”。举个例子:

namespace ns {
    class MyPushButton : public QPushButton {
        // ...
    }
}

// ...
qApp->setStyleSheet("ns--MyPushButton { background: yellow; }");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

设置对象的属性

  从4.3以后,任何使用Q_PROPERTY宏声明的属性都可以使用qproperty-语法。举个例子:

MyLabel { qproperty-pixmap: url(pixmap.png); }
MyGroupBox { qproperty-titleColor: rgb(100, 200, 100); }
QPushButton { qproperty-iconSize: 20px 20px; }
原文转载自:http://blog.csdn.net/matchyang/article/details/47703469

你可能感兴趣的:(QT开发)