学习Qss--选择器

一、通用选择器

通用选择器又叫通配符选择器;
格式

* { attribute: value; }

通用选择器用(*)来表示,它表示匹配程序中所有的widget。
注意点:由于通用选择器会匹配所有的widgets,效率较低,因此应该尽量减少或者不用
一般用法:通用选择器一般用来给应用程序设置统一的字体,例如:

* { font: normal 20px “微软雅黑”; }

这条语句表示将程序中所有widget的字体大小都设置为20px大小,字体采用微软雅黑。

二、类型选择器

格式

className { attribute: value; }

类名即Widget类名,由QObject::metaObject()::className获取,类型选择器匹配所有该类以及该类的派生类的对象,例如:

QPushButton
{
	color: blue;
}

这条语句表示,程序中所有的QPushButton类和它的派生类的对象,它们的前景色(即文字颜色)被设置为蓝色。
注意点:Qt样式表使用widget的QObject::className()来决定何时应用类型选择器。当自定义控件在命令空间之中(或它是一个嵌套类),QObject::className()会返回(::),这与子控件选择器相冲突,为了解决这个问题,当为命名空间中widget使用类型选择器时,我们必须将"::“替换成”--",例如:

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

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

一般用法:类型选择器会匹配所有该类以及该类的派生类的对象,所以我们在程序中,有时为了统一一些具有相似性的控件的样式,可以使用类型选择器,如,我们想要为QSpinBox,QDoubleSpinBon,QDateTimeEdit,QDateEdit,QDataEdit等这些编辑框的控件设置一些相同的样式,因为它们都是QAbstractSpinBox类的派生类,因此可以如下写:

QAbstractSpinBox
{
	min-height: 30px;
	max_height: 30px;
	border-width: 1px;
	rder-style: solid;
	order-color: gray;
	padding: 0px;
}

三、类选择器

格式

.className {attribute: value; }

这里的类名与类型选择器中的类名一样,不同的是,类选择器的类名前面有一个(.),这种选择器只会匹配该类的所有对象,而不会匹配其派生类的对象。例如:

.QPushButton
{
	color: blue;
}

一般用法:类选择器提供了一种匹配该类的对象但不会匹配派生类的方法,通常用来特例化拥有派生类的类对象,但不仅限于此。例如在应用程序中,使用QFrame作为容器widget,此时想要对它设置一些样式,但又不想影响它的子类对象(QLable、QAbstractScrollArea等等),那么就可以使用类选择器给所有的QFrame设置相同的样式,例如:

.QFrame
{
	padding: 15px 25px;
}

四、ID选择器

格式

#ID { attribute: value; }

这里的ID指的是objectName,每个QObject类及其派生类都有一个属性,“#”+objectName构成了ID选择器,它匹配所有objectName为ID选择器所指定的名称的对象,为其设置样式,例如:

#button_1
{
	color: red;
}

注意点

  1. objectName是大小写敏感的;
  2. "#"与ID之间不可以有空格;
  3. 由于objectName是所有QObject类对象的一个属性,在运行过程中可以改变,所以一般情况下,要使用ID选择器时,保证objectName不要在运行时被改变,否则重新加载stylesheet文件时,对应的ID选择器将不会匹配到原来的控件。
  4. 由于objectName允许字符串中含有空格,但是ID选择器汇总,ID是从紧跟#后的第一个字符开始直到遇到空格或"{"之间的字符串,因此,如果是为了使用ID选择器而设置objectName,则objectName中不能含有空格。
  5. 由于任何对象的objectName都可以出现重复,因此在设置objectName时,尽量保持其唯一性。
  6. Qt官方给出的ID选择器的格式为:
    className#ID {attribute: value; }
    
    但实际上不加类名也是可以的(加了类名的ID选择器在CSS中被称为交集选择器),在正式开发中,还是建议加上类名,因为这样可以看出这个ID选择器所匹配的对象的类型,有利于提高阅读性。
    基于以上特点,我们在设置objectName时,一般使用下划线"_"连接的多个单词表明此对象的功能。

一般用法:ID选择器一般用于比较特殊的控件设置样式,例如在应用程序的某个页面中,需要突出一个重要的按钮,那么此时我们可以给这个按钮设置一个独特的样式用以提醒用户,如:

QPushButton#settings_popup_fileDialog_button
{
	min-height: 31px;
	min-width: 70px;
	border: 1px solid black;
	color: #FOFOFO;
	min-height: 10px;
	border-radius: 3px;
	background: qlineargradient(spread: pad, x1:0,y1:0,x2:0,y2:1,stop:0 #454648,stop:1 #7A7A7A);
}

五、后代选择器

格式

selector1 selector2 { attribute: velue; }

这个选择器表示:在选择器1匹配的所有对象中,找到选择器2匹配的所有后代对象,并给它们设置样式。
注意点

  1. 后代选择器必须使用空格隔开每个选择器;
  2. 后代选择器可以通过空格一直延续下去,例如:
    selector1 selector2 ... selectorN { attribute: velue; }
  3. 顾名思义,后代选择器不仅包含“儿子”,还包含“孙子”,“重孙子”等,一般来说,只要B控件显示在A控件上,那么B控件就是A控件的后代。
  4. 后代选择器不仅可以使用类型选择器,还可以使用类选择器,ID选择器等。
  5. Qt中,各控件的父子关系:通过简单的验证,各控件的父子关系并非我们在创建对象时所指定的那样,实际父子关系取决于如何布局。
    一般用法:后代选择器一般用于指定类的后代的样式,例如在我的应用程序中,有很多相似的对话框,它们中包含一些样式相同的按钮,那么我可以使用后代选择器为它们指定样式,例如:
BaseDialog QPushButton
{
	min-width: 12px;
	min-height: 40px;
	max-width: 120px;
	max-height: 40px;
	font-size: 20px;
	padding: 0px;
}

六、子元素选择器

格式

selector1>selector2 { attribute: value; }

子元素选择器表示找到指定选择器所匹配的对象中的所有特定直接子元素然后设置属性,即找到选择器1匹配到的对象中的被选择器2匹配到的直接子元素然后设置属性。
注意点

  1. 子元素选择器必须用">“连接,”>"两边有没有空格都可以,但是不建议写空格,因为会与后代选择器的连接符混淆;
  2. 子元素选择器只会查找“儿子”,不会查找其他后代;
  3. 子元素选择器不仅可以使用类型选择器,还可以使用类选择器,ID选择器;
  4. 子元素选择器不能通过">“一直延续下去,只能有一个”>";
  5. 由于Qt中有继承关系的Widgets较多,在使用子元素选择器时,请特别注意继承关系
    比如我只想选中QGroupBox中的QPushButton
    那么我可以写成:QWidget>QPushButoon{ color: red; } ①
    也可以写成QGroupBox>QPushButton{ color: red; } ②
    这是因为QGroupBoxQWidget的派生类,类型选择器QWidget会选中所有它的派生类对象,这些对象中包括QGroupBox,因此写法①会将所有的QPushButton的前景色设置为红色。
    鉴于此种情况,在使用子元素选择器时,使用类选择器替代类型选择器。
    一般用法:子元素选择器一般用于一些特定布局条件中的控件,例如,我想给直接布局在QGroupBox的QCheckBox设置一些特定属性,那么可以这么做:
.QGroupBox>.QCheckBox
{
	color: blue;
}

七、属性选择器

格式

[attribute=value]{ attribute: value; }
[attribute|=value]{ attribute: value; }
[attribute~=value]{ attribute: value; }

attribute=value表示匹配有特定属性attribute,并且值为value的所有控件,然后设置样式;
attribute|=value表示匹配有特定属性attribute,并且值以value开头的所有控件,然后设置样式;
attribute~=value表示匹配有特定属性attribute,并且值包含value的所有控件,然后设置样式。
注意点
1、 attribute|=value表示attribute属性的值以value开头,无论value后面还有没有值,或者value后面是什么,均能匹配到,例如:

[objectName|="button"]
{
	color: red;
}

这表示将objectName属性以button开头的所有控件的前景色设置为红色。
2、 attribute~=value表示attribute属性的值中包含value,这里要注意的是value必须是独立的单词,也就是包含value并且value是被空格隔开的,例如:

[objectName~="button"]
{
	color: red;
}

在代码中,设置的objectName的语句为:

btn1->setObjectName("button123");
btn2->setObjectName("abc button 2");

结果只会匹配到btn2所指的对象
3、官方文档的解释:通常情况下,这里的属性指的是,使用Q_PROPERTY宏声明的属性,并且属性类型要受QVariant::toString()支持。
这个选择器类型也可以用来判断动态属性,要了解更多使用自定义动态属性的细节,请参考使用自定义动态属性。
处理使用=,还可以使用~=来判断一个QStringList中是否包含给定的QString。
警告:如果在设置了样式表后,相应的属性值发生率改变(如flat变成了"true"),则有必要重新加载样式表,一个有效的方法是,取消样式表,再重新设置一次,下面的代码是其中的一种方式:

style()->unpolish(this);
style()->polish(this);

一般用法:属性选择器一般不常用,如果要用,可以参照官方文档的方法使用

八、并集选择器

格式

selector1,selector2,selector3{ attribute: value; }

并集选择器表示,将每个单独选择器匹配到的控件放在同一结果集中,并给结果集中的每个控件都设置声明语句中的样式。
注意点

  1. 并集选择器必须使用","来连接不同的选择器;
  2. 并集选择器可以使用类选择器,类型选择器,ID选择器,属性选择器等。

一般用法:主要用于给具有相同属性并且外观相似的控件设置样式,例如:

.QLineEdit,.QComboBox
{
	border: 1px solid gray;
	background-color: white;
}

九、子控件选择器

格式

类型选择器::子控件{ 属性:; }
类选择器::子控件{ 属性:; }

表示对类型选择器或类选择器指定的所有控件的子控件设置样式;
Qt官方说明
为了样式化你的复杂widget,很有必要使用widget的subcontrol,比如QComboBox的drop-down部分或者是QSpinBox的上和下箭头。选择器也许会包含subcontrols用于限制widget的subcontrols,例如:

QComboBox::down-arrow
{
	image: url(:/res/arrowdown.png);
}

上述规则样式话所有QComboBox的drop-down部分,虽然双冒号(::)让人联想到CSS3的伪元素语法,但是Qt的Sub-Controls跟它是不一样的。
Sub-Control始终相对于另一个元素来定义一个参考元素。这个参考元素可以是一个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;
}

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;
}

绝对定位方案(position:absolute),使得Sub-Control的position和size基于其参考元素而改变。
一旦定位,它们将会与widget同等对待并且使用盒子模型来样式化。
查看Sub-Control列表以了解哪些sub-control是被支持的,并且可以查看自定义QPushButton的菜单指示器Sub-Control来了解一个实际的使用例子。
注意:像QComboBox和QScrollBar这样的复杂部件,如果sub-control的一项属性是自定义的,那么其他所有的属性跟sub-control也都应该自定义。

十、伪类选择器

格式

类型选择器:状态{ 属性:; }
类选择器:状态{ 属性:; }

表示对类型选择器或类选择器指定的所有控件设置它在指定状态的样式。
Qt官方说明
选择器也许会包含基于widget的state的程序限制规则的伪状态。伪状态以冒号(:)作为分隔紧跟着伪选择器。举个例子,下面的规则在鼠标悬浮在QPushButton的上方时生效:

QPushButton:hover { color: white }

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

QRadioButton:!hover{ color: red }

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

QCheckBox:hover:checked { color: white }

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

QPushButton:hover:!pressed { color: blue }

如果有需要,可以使用逗号来表示逻辑或,即并集选择器

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

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

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

十一、没有选择器的情况

如果在C++的代码中直接调用控件对象的setStyleSheet函数来设置样式,但样式中没有任何选择器,例如下面这样:

btn1->setStyleSheet("color: green;");

即使这种写法可以生效,但它不符合语法规则,因此不推荐使用。
经过测试,这样的语句被忽略的选择器相当于通用选择器或下面例子中的选择器,假如btn1是一个QPushButton对象的指针,那么这条语句等价于:

btn1->setStyleSheet("QPushButton,QPushButton *{ color: green;}");

十二、选择器的匹配规则

需要完成一个界面,如下图所示:
在这里插入图片描述
这里用户名输入框是一个QComboBox对象,密码输入框是一个QLineEdit对象,它们的父控件是一个QDialog,有这样一个需求:给这两个输入框设置相同的边框属性:1个像素宽的蓝色实线框,为了方便更改风格,我有一个qss文件,将所有样式都写在这个文件里,这时,观察发现,这两个控件都是QDialog的子控件,于是可以用后代选择器或者子元素选择器,如下:
第一种:

QDialog QComboBox,QLineEdit
{
	border:1px solid blue;
}

第二种:

QDialog>QComboBox,QLineEdit
{
	border:1px solid blue;
}

当写完并运行程序后,发现无论采用哪种写法QComboBox是正常的,但是我的程序界面中,其他所有的QLineEdit的边框都变成了1个像素宽的蓝色实线框,而这并不是我想要的效果。
因此对于上面的现象,我们很容易得出结论:多个选择器组合使用时,它们的结合方向是自左向右,而不是我们认为的自右向左。也就是说,这两个选择器分别被理解为{ QDialog QComboBox },QLineEdit和{ QDialog>QComboBox },QLineEdit。
其实,这应该与CSS的选择器匹配规则是一样的,是为了提高效率的一种做法,具体原因在此不细谈。
正确的写法应该是:

QDialog QComboBox,QDialog QLineEdit 
{
	border: 1px solid blue;
}

QDialog>QComboBox,QDialog>QLineEdit
{
	border: 1px solid blue;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章