打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
GUI学习之三十四

今天是一个大课题:QSS样式表

一.概念:

QSS是Qt Style Sheet——Qt样式表,是用来自定义控件外观的一种机制;可以把他类比成CSS,但是不及其功能强大。

二.使用:

我们做一个模板,可以在后面来演示

  1. from PyQt5.Qt import *
  2. import sys
  3.  
  4. class Window(QWidget):
  5. def __init__(self):
  6. super().__init__()
  7. self.UI_test()
  8. self.resize(800,600)
  9.  
  10. def UI_test(self):
  11. box1 = QWidget(self)
  12. box2 = QWidget(self)
  13.  
  14. layout = QVBoxLayout()
  15. layout.addWidget(box1)
  16. layout.addWidget(box2)
  17.  
  18. self.setLayout(layout)
  19.  
  20. label1 = QLabel('标签1',box1)
  21. btn1 = QPushButton('click1',box1)
  22. btn1.move(150,50)
  23.  
  24. label2 = QLabel('标签1', box2)
  25. btn2 = QPushButton('click1', box2)
  26. btn2.move(150, 50)
  27.  
  28. pass
  29. if __name__ == '__main__':
  30. app = QApplication(sys.argv)
  31. window = Window()
  32. window.show()
  33. sys.exit(app.exec_())

演示模板

  1. mainwindow--
  2. |
  3. |
  4. |box1-----------
  5. | | -label1
  6. | |
  7. | | -btn1
  8. |
  9. |box1-----------
  10. | -label1
  11. |
  12. | -btn1

1.局部设置

局部设置是指定需要设置外观的控件,直接调用控件的方法就好了

  1. QWidget.setStyleSheet()

局部设置的作用域是控件本身和子控件

  1. box1.setStyleSheet('background-color:red')
  2. box2.setStyleSheet('background-color:orange')

可以发现整个控件内部的子控件都被设置了。

还有一种方式,在定义的时候加上选择器

  1. box1.setStyleSheet("QPushButton {background-color:yellow};")
  2. box2.setStyleSheet("QLabel {background-color:red};")

这样就可以把指定类型的控件的样式设定

2.全局设置

比方我们定义一个新的btn3,但是父控件不是主窗口

  1. self.btn3 = QPushButton('btn3')
  2. self.btn3.show()
  3. #注意:1btn3不属于self,要主动被show()才可以
  4. # 2btn要被调用,如果只被定义在show()以后会直接被释放掉

运行的效果是这样的,btn3是个独立的控件

这个时候,如果用父控件的设置效果

  1. self.setStyleSheet("QPushButton {background-color:yellow};")

只有self内的控件会变化

如果需要全局设置的话,要指定全局的QApplication对象,调用其对应的setStyleSheet方法。

  1. app = QApplication(sys.argv)
  2. window = Window()
  3. window.show()
  4. app.setStyleSheet("QPushButton {background-color:yellow};")#调用全局的控件效果设置
  5. sys.exit(app.exec_())

这样就是应用程序内的所有控件都被设置了。

3.全局定位设置

还有一种情况,在全局设置的时候我们可以定位一个控件进行设置,但第一步是要将该空间定义一个objectname

  1. label1.setObjectName('l1')
  2. self.setStyleSheet("QPushButton {background-color:yellow;} "
  3. "QLabel#l1 {background-color:red;}")

控件类型加了个ID选择器

4.常规使用方法

由于一般情况下qss的字符串都比较长,为了方便使用我们一般把字符串另存在一个文件里(常规情况可以把文件后缀名定为.qss)

  1. with open('test.qss','r') as f:
  2. qss = f.read()
  3. self.setStyleSheet(qss)
  4.  
  5. #test.qss
  6. QLabel#l1 {
  7. background-color:yellow
  8. }
  9. QPushButton#b2{
  10. background-color:red
  11. }

就把样式和页面的逻辑分开了。如果更改只要改qss文件就好了,比较便于修改。还有一点要注意的基础知识:不同控件的objectname可以是一样的!

三.QSS语法

QSS组成是由下面几部分组成

  QSS选择器——用来再一次选择控件,可以进行二次筛选

  QSS伪状态——指定不同的状态

  QSS声明——指定样式的字符串

  我们下面一个个来讲

四.QSS选择器

1.作用:QSS选择器主要用来指明哪些控件会收到样式的作用,分为下面几类,我们通过改上面的qss文件来分别演示

  通配符选择器

  类型选择器

  类选择器

  ID选择器

  属性选择器

  后代选择器

  字选择器

  子控件选择器

2.通配符选择器是匹配所有的控件,用星号表示

  1. * {
  2. background-color:yellow
  3. }

3.类型选择器是通过控件类型来匹配控件的(包括子类)

  1. QWidget {
  2. background-color:yellow
  3. }

在这个例子里,因为QWIdget里有QLabel和QPushbutton两个子类,所以所有的控件都会生效。(注意是父子类继承的关系而不是从属关系)

4.类选择器也是通过控件类型来匹配控件的,但不同的是不包含子类,语法是在类前面加了个.(是个点)

  1. .QWidget {
  2. background-color:yellow
  3. }
  4. 注意类前面有个点

这样就只对QWidget生效,btn和label是不会变化的。

5.ID选择器是和结合控件的objectname来匹配控件的,qss里objectname前加个井号来表示,不同控件的objectname是可以相同的

  1. btn2.setObjectName('blue')
  2. btn1.setObjectName('blue')

qss的内容

  1. #blue {
  2. background-color:blue
  3. }

6.属性选择器是结合控件的属性值来匹配控件的,,首先要设定控件的属性,qss里属性用[proterty = attitude]来限制

  1. label1.setProperty('notice_level','error')
  2. label2.setProperty('notice_level','warning')

然后定义qss文件

  1. .QLabel {
  2. background-color:pink;
  3. }
  4.  
  5. .QLabel[notice_level='warning'] {
  6. border:5px solid yellow;
  7. }
  8.  
  9. .QLabel[notice_level='error'] {
  10. border:5px solid red;
  11. }

这里还有个用法,就是qss内只定义属性值,只要有这个属性的控件就可以被选中

  1. .QLabel [notice_level]{
  2. background-color:pink;
  3. }
  4.  
  5. .QLabel[notice_level='warning'] {
  6. border:5px solid yellow;
  7. }
  8.  
  9. .QLabel[notice_level='error'] {
  10. border:5px solid red;
  11. }

第一个qss定义了只要有novice_level这个属性的控价都是生效的。

上图中的标签3是直接创建的,并没有加属性,所以只有标签1和2有背景色。注意语法:控件和中括号之间是不能有空格的

7.后代选择器是通过父控件(直接或间接)子控件来筛选控件,前面的代码里主界面和box1,box1和label1之间都是直接包含的,而主界面和label1是间接包含的关系。

例如我们想把box2里的标签设置个背景色,要怎么做?

首先给box2设置好objectname

  1. box2.setObjectName('box2')

然后定义qss文件,就可以了,注意语法(空格的位置)

  1. QWidget#box2 QLabel {
  2. background-color:pink;
  3. }

如果我们新建一个box3,一个label3放在box3里

  1. box3 = QWidget(box2)
    box3.move(300,0)
  2. label3 = QLabel('label3',box3)

因为box2是label3的间接父关系,索引上面的qss对label3也是生效的。

8.子选择器是通过父控件的直接子控件来筛选控件的。语法是父控件后跟一个大于号>,还是上面那个带box3的例子,qss文件是这样的

  1. QWidget#box2>QLabel {
  2. background-color:pink;
  3. }

这样就只对box2里的QLabel控件生效,label3作为box的间接子控件是不变化的

9.子控件选择器用来选择一个复合控件上的子控件,语法是两个冒号::

  1. 同一行中是有相同子控件的控件
  2. QCheckBox,QRadioButton
  3. QCombBox,
  4. QSpinBox,QDateEdit,QTimeEdit,QDateTimeEdit
  5. QSlider
  6. QProgressBar
  7. QScrollBar
  8. QGroupBox
  9. QTableView
  10. 等待

常用复合控件

我们可以通过特定的控件选择空间的子控件比如我们创建个checkbox控件,把复选框的框框可以改下样式(加了个图片)

  1. QCheckBox::indicator {
  2. image:url(../open.png);
  3. width:20px;
  4. height:20px;
  5.  
  6. }

看下效果

但是会发现用鼠标点击是不是没效果了,如果改这种效果,我们就需要用到下一节的内容:qss伪装态,我们后面再讲。

10补充

  上面讲的各种选择器是可以叠加使用的,用逗号分隔就可以了

  1. QWidget#btn1,#btn2 {
  2. background-color:pink;
  3. }

五.QSS伪装态

  我们在上面一节第9条提到了伪装态这个概念,他是限制控制只能在某种状态下,被样式表作用,语法是冒号:后面加关键字

  1. 选择器:伪装态

下面是常见的伪装态

  1. :checked button部件被选中
  2. :unchecked button部件未被选中
  3. :disabled 部件被禁用
  4. :enabled 部件被启用
  5. :focus 部件获得焦点
  6. :hover 鼠标位于部件上
  7. :pressed 部件被鼠标按下
  8. :indeterminate checkbox或radiobutton被部分选中
  9. :off 部件可以切换,且处于off状态
  10. :on 部件可以切换,且处于on状态

常见的伪装态

这个就不演示了。但是要有注意的地方:

1.不同的控件会有某种特定的状态,具体的要看官方文档

2.可以用!否定,比如!checked表明没被选中

3可以连接使用:

  1. :hover:checked 表明鼠标指向并且选中时
  2. :hover:!checked鼠标经过但没有选中

六.QSS声明

  QSS声明指明了控件会作用什么样的样式,以类似于字典的形式存在(分号分隔,而字典是逗号)

  1. {
      key:value;
  2. key:value;
  3. }

  一般控件都符合名字叫做盒子模型的布局样式,我们先看看这个样式的概念

其中margin——外边框

border——内边框

  content——内容

一个控件的尺寸定义好以后,就是上面图中虚线的尺寸,而定义了外边距'、边框和内边距以后内容矩形是不停的被压缩的,整体的尺寸是不会变的

1.边框相关

针对边框来说也有三个参数:样式,宽度,颜色。而每个参数的设定可以一次设定四个参数(上右下左,以空格分割),也可以独自设置

  1. QLabel {
  2. background-color:yellow;
  3. border-width:5px;
  4. border-right-style:dotted;
  5. }

上面的代码就是同时设置四个方向的边框样式

下面的就是样式的代码

  1. none :  无边框。与任何指定的border-width值无关
  2. hidden :  隐藏边框。IE不支持
  3. dotted :  在MAC平台上IE4+与WINDOWS和UNIX平台上IE5.5+为点线。否则为实线(常用)
  4. dashed :  在MAC平台上IE4+与WINDOWS和UNIX平台上IE5.5+为虚线。否则为实线(常用)
  5. solid :  实线边框(常用)
  6. double :  双线边框。两条单线与其间隔的和等于指定的border-width值
  7. groove :  根据border-color的值画3D凹槽
  8. ridge :  根据border-color的值画菱形边框
  9. inset :  根据border-color的值画3D凹边
  10. outset :  根据border-color的值画3D凸边

而如果想独立设置,也可以分别按下面的方法指定

  1. border-top-style
  2. border-right-style
  3. border-bottom-style
  4. border-left-style

而宽度的设定也可以直接指定,也可以指定边框

  1. border-top-width
  2. border-right-width
  3. border-bottom-width
  4. border-left-width

这里还有个要点,px(像素值) 和em(相对长度单位)

其中还有个换算单位

  1. 1em=16px

最后的颜色和前面的都一样,可以统一设置也可以独立设置,但是还有一点,除了直接指定颜色还可以直接指定rgb的值

  1. QLabel{
  2. border-left-color:reb(255,255,0)
  3. }

当然也可以设置16进制的值

  1. #00ff00

最后看一下渐变色的设定。

a.线性渐变

线性渐变的思路是按下面的坐标系变化的

在定义坐标的时候,我们通常把x1,y1的值定为0,x2和y2的值定成1,然后可以指定好中间的颜色就可以了

  1. QLabel {
  2. background-color:qlineargradient(x1:0, y1:0, x2:1, y2:1,stop:0 red,stop:0.4 gray,stop:0.8 orange,stop:1 green);
  3.  
  4. }

比方上面的qss文件,出来的效果就是这样的从0到1中间分了0.4和0.8两个点,颜色定义了会和橙色。

这里有个隐藏用法:如果我们定义了x2或y2的值为0就成了垂直或水平渐变色的效果

b.辐射渐变

辐射渐变的思路是这样的

其中XcYc是圆心的坐标点,r为渐变的半径,XfYf为焦距点(可以以为是颜色最浓的地方)

  1. QLabel {
  2. background-color:qradialgradient(cx:0.1,cy:0.1, radius:0.5,fx:0.9,fy:0.9,stop:0 red,stop:0.5 yellow,stop:1 orange);
  3.  
  4. }

出来的效果

如果我们把cxcy都设为0.5,则是从中间开始变色的

c.角度渐变

角度渐变是先确认个中心点(Xc,Yc),再确定出起始角度(0度为水平向右,逆时针旋转),然后围着原点转一圈开始渐变

  1. QLabel {
  2. background-color:qconicalgradient(cx:0.5,cy:0.5, angle:90,stop:0 red,stop:0.5 yellow,stop:1 orange);
  3.  
  4. }

然后我们在看一看边框圆角

因为默认情况控件的边框显示的都是矩形,但有些时候我们希望把空间的角变成圆弧,那有什么参数呢?

从上面的图可以看出来,我们以不同的半径画控件边框的内切圆,由于是内切,三个圆的圆心都在角平分线上,要想要不同的弧度,只需指定好半径即可(也可以指定角设定)

  1. border-radius
  2. border-top-left-radius
  3. border-top-right-radius
  4. border-bottom-right-radius
  5. border-bottom-left-radius

如果把半径设为控件的一般,效果就是圆了。

  1. QLabel {
  2. border-style:groove;
  3. border-width:22px;
  4. border-radius:150px
  5.  
  6. }

因为label的尺寸为300*300,我们把半径设成150出来的效果就是圆形了

边框图片

然而有些时候边框效果不太容易通过效果设置,比如这个效果

那么我们就可以直接设定边框图片

  1. QLabel {
  2. background-color:yellow;
  3. border-image:url(无标题.png);
  4. }

但是要注意一下qss里是有个背景色的,由于图片背景不是透明的,就会把背景色遮盖

还有一点,如果设置的图片如果尺寸比较小的话填满控件后是会被拉伸的,例如我们把下面的图片(20*20像素)

,添加在上面的label控件里结果就是被拉伸了

然后我们可以定义一个裁剪值和重复策略,意义是这样的:

裁剪值:上——距离上边的线(像素值)

    下——距离下边的线(像素值)

    左——距离左边的线(像素值)

    右——距离右边的线(像素值)

重复  :round——平铺

     repeat——重复

       stretch——拉伸

我们来结合一个图来看吧

我们用上面定义的分割线把一副图分割成了9份,然后四个角上的图是不会被拉伸的,剩下的2,4,6,8是会按照定义的拉伸策略被拉伸。这个没有比较好的例子就不演示了。

  1. QLabel {
  2. background-color:yellow;
  3. border-image:url(无标题.png)30px 30px 30px 30px round;
  4. border-width:35px
  5. }

2.外边距(Margin)

外边距和前面说的一样,可以统一设置也可以分开设置

  1. 统一设置
    margin (可以定义不同值,上、右、下、左)
    分开设置
  2. margin-top
  3. margin-right
  4. margin-bottom
  5. margin-left
  1. QLabel {
  2. background-color:yellow;
  3.  
  4. border-style:solid;
  5. border-width:10px;
  6. margin:20px 40px 80px 160px
  7. }

可以看出来控件已经被截成矩形的了

3.内边距

内边距限制了控件内容显示的区域范围,设置的方法和上面的外边距是一样的

  1. 统一设置
  2. padding (可以定义不同值,上、右、下、左)
  3. 分开设置
  4. padding-top
  5. padding-right
  6. padding-bottom
  7. padding-left

4.背景

背景(background)分下面几条

  1. background
  2. background-color #颜色
  3. background-image #图片
  4. background-repeat #重复
  5. background-position #位置
  6. background-origin
  7. background-clip
  8. background-attachment

我们一点点来搞清楚

a.background-color是没什么好讲的,可以直接加颜色,也可以加个rgb定义颜色

b.图片和下面几个可以一起来讲,比方我们设定了个背景图片

  1. QLabel {
  2. background-image:url(test.png)
  3. }

效果如下:

是不是都重复了,这时候就需要用到重复的定义了(默认情况是xy轴方向都重复的)

  1. background-repeat:no-repeat #只显示一张(默认位置在左上角)
  2. repeat-x #只重复x轴方向
  3. repeat-y             #只重复y轴方向
  4. repeat-xy             #重复xy轴两个方向

因为如果我们用不重复的时候图片显示的位置是左上角(为了直观我们加一个背景色来表明控件的位置和外观)

  1. QLabel {background-color:yellow;
  2. background-image:url(test.png);
  3. background-repeat:no-repeat
  4. }

显示效果:

如果我们想要改变图片的位置就可以通过下面的方法

  1. background-position:
  2. right
  3. top
  4. bottom
  5. left
    middle

用下面的qss代码设置

  1. QLabel {background-color:yellow;
  2. background-image:url(test.png);
  3. background-repeat:no-repeat;
  4. background-position:left middle
  5. }

出来的效果

注意看红框框,因为我们设置的是背景,是不会遮盖前面层的文本的。

下面看一下参照位置的用法

  1. background-origin:
  2. border
  3. padding #默认值
  4. content

我们把边框显示出来以后加上上面的图

  1. QLabel {background-color:yellow;
  2. border:20px double red;
  3. background-image:url(test.png);
  4. background-repeat:no-repeat;
  5. }

可以看出来,图片是贴着边框内部的

最后一个

  1. background-attachment:
  2. scroll
  3. fixed

表示背景是否跟随控件多余的部分滚动而滚动。如果我们的控件是一个可以滚动的控件(类似于QTextEdit)默认的scroll是背景随着控件的滚动而滚动的

5.字体设置和前景色

字体设置的的方法和setfont()方法差不多,qss文件

  1. #统一设置
  2. font
  3. #独立设置
  4. font-family
  5. font-size
  6. font-style
  7. font-weight

其中字体形式分下面几种

  1. font-style:
  2. normal
  3. italic #斜体
  4. oblique #倾斜

而字体的粗细除了可以用下面的单词表示,也可以直接定义数值

  1. font-weight:
  2. bold #粗体
  3. bolder #更粗
  4. lighter #更细
  5. 100
  6. 200
  7. 300
  8. 400



  9. 由粗到细,400为normal,700等同于bold

还可以直接指定前景色

  1. color

因为大部分的控件前景都为字符,设置了前景色就相当于改变了字符的颜色

看一下效果

  1. QLabel {font-family:隶书;
  2. font-size:30px;
  3. font-style:oblique;
  4. font-weight:bold;
  5. color:red
  6. }

效果图就不放了,自己脑补一个红色的Label字符串好了。

6.最大最小

最大最小和直接调用设置最大最小尺寸的方法一样

  1. min-width:
  2. max-width:
  3. min-height:
  4. max-height:

7.子控件控制

整体来看子控件控制Subcontrol有下面几种模式

  1. Subcontrol-Origin
  2. Subcontrol-Position
  3. 还可以细微调整
  4. Top Bottom
  5. Left Right

我们用一个spinbox来演示上面的效果

  1. from PyQt5.Qt import *
  2. import sys
  3. class Window(QWidget):
  4. def __init__(self):
  5. super().__init__()
  6. self.UI_test()
  7.  
  8. def UI_test(self):
  9. spin = QSpinBox(self)
  10. spin.resize(300,300)
  11. spin.move(50,50)
  12.  
  13. spin.setStyleSheet("""
  14.  
  15. """)
  16.  
  17. if __name__ == '__main__':
  18. app = QApplication(sys.argv)
  19. window = Window()
  20. window.show()
  21. sys.exit(app.exec_())

然后我们通过改变qss代码来改变他的效果,正常情况

  1. QSpinBox {
  2. font-size:20px;
  3. color:red;
  4. border:10px double green;
  5. border-radius:10px
  6. }

效果如下

因为上下按钮是属于前景的,在改变了前景色的时候箭头的颜色也变了。

如果我们想改变上箭头的效果可以使用前面讲到的子控件选择器

  1. QSpinBox {
  2. font-size:20px;
  3. color:red;
  4. border:10px double green;
  5. border-radius:10px
  6. }
  7. QSpinBox::up-button{
  8. width:50px;
  9. height:50px;
  10. }

效果:

那我们想改变一下他们的位置就要用到这里的子控件控制了

  1. QSpinBox {
  2. font-size:20px;
  3. color:red;
  4. border:10px double green;
  5. border-radius:10px
  6. }
  7. QSpinBox::up-button{
  8. width:50px;
  9. height:50px;
  10. subcontrol-position:left middle
  11. }
  12. QSpinBox::down-button{
  13. width:50px;
  14. height:50px;
  15. subcontrol-position:right middle
  16. }

效果:

而这一节说的微调主要是和伪装态联系用的,比方鼠标指向后bottom 10px意思就是鼠标指向控件后控件向下移动10个像素(这里还有个设定的东西,position:relative或者position:absolute),其中relative是相对原先控件的位置变化的像素值,而absolute就结合了origin的位置了。

  1. QSpinBox::down-button:hover {
  2. position:absolute;
  3. top:100px;
  4. width:50px;
  5. height:50px;
  6. subcontrol-position:right middle
  7. }

上面就是语法结构的参考形式。

上面讲的就是qss语法的基本结构,具体的伪装态,子控件形式什么的可以看下Qt的官方文档

七.注意事项

1.级联:

  QSS可以在QApplication、父控件、子控件中设置,这个我们在上面已经说过了。而一个控件的最终样式,会收到父控件以及QApplication的影响。

2.冲突

  如果一个控件作为后代控件,被多个控件影响,则会不同属性相互叠加,相同属相产生覆盖。这里还要考虑到特异性:同时设置的话要看那个优先级比较高:比如下面两个按钮

  1. btn = QPushButton('b1',self)
  2. btn2 = QPushButton('b2',self)
  3. btn2.move(100,0)
  4. btn2.setObjectName('btn2')
  5.  
  6. self.setStyleSheet("""
  7.  
  8. QPushButton {
  9. background-color:red
  10. }
  11.  
  12. QPushButton#btn2 {
  13. background-color:green
  14. }
  15. """)

由于btn2是有特异性的,所以优先级比较高。出来的效果就是btn1为红色,btn2为绿色。

而如果一样的特异性,那就取最后一个。

八.三方包

有些时候我们可以通过导入三方包来使用别人已经做好的qss代码,这里我在命令行可以安装一个包

  1. pip install qdarkgraystyle

然后在最后就可以直接使用(这里就放出来最后一段的代码)

  1. if __name__ == '__main__':
  2. app = QApplication(sys.argv)
  3. import qdarkgraystyle
  4. app.setStyleSheet(qdarkgraystyle.load_stylesheet_pyqt5())
  5. window = Window()
  6. window.show()
  7. sys.exit(app.exec_())
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Qt控件外观样式设置一览表附丰富模板qss
使用Qss设置窗体样式
Qt之界面换肤的两种方式
Qt实现FlatUI样式(开源)
前端代码标准最佳实践:CSS篇
编码规范(Css)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服