学习Qss--Qss的特性

一、层叠性

qss的语法来源于css,而css的全称是Cascading StyleSheet,翻译过来叫做层叠样式表,也叫级联样式表。层叠性是css处理冲突的一种能力,只有在多个选择器匹配到同一个控件时才会发生层叠性,例如:

btn1->setStyleSheet("QPushButton{ color: blue; }");
btn1->setStyleSheet(".QPushButton{ color: green; }");

这两个选择器匹配到了同一个按钮,结果是后面的样式覆盖了前面的,这就是层叠现象。

二、继承性(Qt-Version>=5.7)

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

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

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

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

注意QGrouBox和*之间的空格。
与此相反,使用QWidget::setFont()可以设置字体包括孩子的字体,使用QWidget::setPalette()可以设置调色板包括孩子的调色板。
如果想要字体和调色板被孩子继承,可以给QApplication设置Qt::AA_UseStyleSheetPropagationInWidgetStyles(Qt5.7 加入)属性,例如:

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

三、优先级

当一个控件被多个选择器选中并且设置了相同的属性(值不同)时,不能仅仅根据设置样式语句出现的先后顺序进行层叠,那么控件的样式如果确定,于是引出了选择器的优先级问题。一般通过下面两步进行选择器优先级的判定。
第一步:设置方式所产生的优先级问题
在CSS中,有如下层叠优先级规则:

内联样式 > 内部样式 > 外部样式 > 浏览器缺省

而在Qss中,这个规则表现为:

给控件直接设置的样式 > 给QApplication设置的样式

就是说,调用控件的setStyleSheet设置的样式的优先级永远高于给QApplication设置的样式,即使QApplication中的选择器优先级更高。
第二步:样式表本身的优先级问题
当设置方式相同,且几个样式规则为同一个控件的同一个属性指定不同的值时,就产生了冲突。此时,如何层叠就要由选择器的优先级来确定。
一般而言,选择器越特殊,它的优先级越高。也就是选择器指向的越准确,它的优先级就越高。

优先级判断的三种方式

  1. 间接选中
    间接选中就是指继承,也就是在Qt5.7及以上版本,程序中给QApplication对象设置了Qt::AA_UseStyleSheetPropagationInWidgetStyles属性时,才会有间接选中。
    如果是间接选中,那么最终的样式就是离目标最近的那个,这里的近指的是两个控件的父子关系。例如一个QPushButton对象被布局在QGroupBox中,而QGroupBox又被布局在QWidget中,此时如果给QGroupBox和QWidget都设置了color属性的颜色,那么无论设置顺序如何,QPushButton的前景色总是表现为QGroupBox设置的颜色,因为QGroupBox显然是离QPushButton最近的那一个。
  2. 相同选择器(直接选中)
    如果都是直接选中,并且都是同类型的选择器,那么写在后面的样式会覆盖掉前面的样式,例如:
    btn1->setStyleSheet("QPushButton{ color: green; }");
    btn1->setStyleSheet("QPushButton{ color: blue; }");
    
    显而易见,btn1的前景色是蓝色。
  3. 不同选择器(直接选中)
    如果都是直接选中,并且不是相同类型的选择器,那么就会按照选择器的优先级来层叠。
    具体的优先级如下:
    ID >> 类型 > 通配符 > 继承 > 默认
    

优先级权重
当多个选择器混合在一起使用时,我们可以通过计算权重来判断谁的优先级最高,从而确定控件的样式。

注意点:只有选择器时直接选中控件是才需要计算权重,否则直接选择器高于一切间接选中的选择器。
优先级权重的计算方式:

  1. 计算选择器中的id选择器数量[=a]
  2. 计算选择器中类选择器的数量+属性选择器的数量[=b]
  3. 计算选择器中类型选择器的数量[=c]
  4. 忽略子控件选择器

串联这三个数字a-b-c就得到优先级权重,数字越大优先级越高。
Qt官方关于冲突解决的说明
当几个样式规则为同一个属性指定不同的值时,就产生了冲突。请考虑下面的样式表:

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

两条规则都匹配名为okButton的QPushButton实例并且冲突于颜色属性。为了解决冲突,我们必须考虑到选择器的特殊性。在上面的例子中,QPushButton#okButton被视为比QPushButton更特殊,因为它(通常)指向一个单一的对象,而不是QPushButton的所有实例。
相似的,指定了伪状态的选择器比没有指定伪状态的更特殊。从而,下面的样式表指明了当鼠标悬浮到QPushButton上方时其字体颜色应该为白色,而其余情况为红色:

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

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

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

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

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

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

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

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

QPushButton {  color: red; }
QAbstractButton { color: gary; }

两条规则都应用于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*/

四、盒模型

4.1、什么是盒模型?

盒模型仅仅是一个形象的比喻,所有的widget都被看做是一个“盒子”,一个盒子包括:外边距,边框,内边距,和实际内容。它们可以看做是有包含关系的矩形,并且这种包含关系是固定不变的。如图所示:
在这里插入图片描述

  • Margin(外边距):与其他盒子之间的距离;
  • Border(边框):外边距与内边距之间的区域。边框有自己的颜色不会受到盒子的背景颜色影响;
  • Padding(内边距):内容和边框之间的区域。会受到背景颜色的影响;
  • Content(内容):盒子的内容,显示文本,图像或其他控件。

除了内容外,其他三个部分均不能单独设置颜色,智能设置其宽度,并且使以像素为单位。

4.2、盒模型中的宽度与高度

在属性中将要学到width,height两个属性,设置的均是盒子的内容的宽高,而我们在C++代码中的窗口的width与height指的是整个盒子的宽度与高度,这一点非常重要。
整个盒子的宽度应该等于:

左外边距+左边框+左内边距+内容宽度+右内边距+右边框+右外边距

同理,整个盒子的高度也是上下外边距,内边距和内容高度的和。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝勒里恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值