GUI學習之三十四——QSS樣式表


今天是一個大課題:QSS樣式表

 一.概念:

QSS是Qt Style Sheet——Qt樣式表,是用來自定義控件外觀的一種機制;可以把他類比成CSS,但是不及其功能強大。

二.使用:

我們做一個模板,可以在后面來演示

from PyQt5.Qt import *
import sys

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.UI_test()
        self.resize(800,600)

    def UI_test(self):
        box1 = QWidget(self)
        box2 = QWidget(self)

        layout = QVBoxLayout()
        layout.addWidget(box1)
        layout.addWidget(box2)

        self.setLayout(layout)

        label1 = QLabel('標簽1',box1)
        btn1 = QPushButton('click1',box1)
        btn1.move(150,50)

        label2 = QLabel('標簽1', box2)
        btn2 = QPushButton('click1', box2)
        btn2.move(150, 50)

        pass
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())
演示模板
         mainwindow--
                    |
                    |
                    |box1-----------
                    |              | -label1
                    |              | 
                    |              | -btn1
                    |
                    |box1-----------
                                   | -label1
                                   | 
                                   | -btn1

1.局部設置

局部設置是指定需要設置外觀的控件,直接調用控件的方法就好了

QWidget.setStyleSheet()

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

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

 

可以發現整個控件內部的子控件都被設置了。

還有一種方式,在定義的時候加上選擇器

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

這樣就可以把指定類型的控件的樣式設定

2.全局設置

比方我們定義一個新的btn3,但是父控件不是主窗口

self.btn3 = QPushButton('btn3')
self.btn3.show()
#注意:1btn3不屬於self,要主動被show()才可以
#     2btn要被調用,如果只被定義在show()以后會直接被釋放掉

運行的效果是這樣的,btn3是個獨立的控件

這個時候,如果用父控件的設置效果

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

只有self內的控件會變化

如果需要全局設置的話,要指定全局的QApplication對象,調用其對應的setStyleSheet方法。

app = QApplication(sys.argv)
window = Window()
window.show()
app.setStyleSheet("QPushButton {background-color:yellow};")#調用全局的控件效果設置
sys.exit(app.exec_())

這樣就是應用程序內的所有控件都被設置了。

3.全局定位設置

還有一種情況,在全局設置的時候我們可以定位一個控件進行設置,但第一步是要將該空間定義一個objectname

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

控件類型加了個ID選擇器

4.常規使用方法

由於一般情況下qss的字符串都比較長,為了方便使用我們一般把字符串另存在一個文件里(常規情況可以把文件后綴名定為.qss)

with open('test.qss','r') as f:
    qss = f.read()
self.setStyleSheet(qss)



#test.qss
QLabel#l1 {
        background-color:yellow
}
QPushButton#b2{
        background-color:red
}

就把樣式和頁面的邏輯分開了。如果更改只要改qss文件就好了,比較便於修改。還有一點要注意的基礎知識:不同控件的objectname可以是一樣的!

三.QSS語法

QSS組成是由下面幾部分組成

  QSS選擇器——用來再一次選擇控件,可以進行二次篩選

  QSS偽狀態——指定不同的狀態

  QSS聲明——指定樣式的字符串

  我們下面一個個來講

四.QSS選擇器

1.作用:QSS選擇器主要用來指明哪些控件會收到樣式的作用,分為下面幾類,我們通過改上面的qss文件來分別演示

  通配符選擇器

  類型選擇器

  類選擇器

  ID選擇器

  屬性選擇器

  后代選擇器

  字選擇器

  子控件選擇器

2.通配符選擇器是匹配所有的控件,用星號表示

* {
        background-color:yellow
}

3.類型選擇器是通過控件類型來匹配控件的(包括子類)

QWidget {
        background-color:yellow
}

在這個例子里,因為QWIdget里有QLabel和QPushbutton兩個子類,所以所有的控件都會生效。(注意是父子類繼承的關系而不是從屬關系)

4.類選擇器也是通過控件類型來匹配控件的,但不同的是不包含子類,語法是在類前面加了個.(是個點)

.QWidget {
        background-color:yellow
}
注意類前面有個點

這樣就只對QWidget生效,btn和label是不會變化的。

5.ID選擇器是和結合控件的objectname來匹配控件的,qss里objectname前加個井號來表示,不同控件的objectname是可以相同的

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

qss的內容

#blue {
        background-color:blue
}

6.屬性選擇器是結合控件的屬性值來匹配控件的,,首先要設定控件的屬性,qss里屬性用[proterty = attitude]來限制

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

然后定義qss文件

.QLabel {
        background-color:pink;
}

.QLabel[notice_level='warning'] {
        border:5px solid yellow;
}

.QLabel[notice_level='error'] {
        border:5px solid red;
}

這里還有個用法,就是qss內只定義屬性值,只要有這個屬性的控件就可以被選中

.QLabel [notice_level]{
        background-color:pink;
}

.QLabel[notice_level='warning'] {
        border:5px solid yellow;
}

.QLabel[notice_level='error'] {
        border:5px solid red;
}

第一個qss定義了只要有novice_level這個屬性的控價都是生效的。

上圖中的標簽3是直接創建的,並沒有加屬性,所以只有標簽1和2有背景色。注意語法:控件和中括號之間是不能有空格的

7.后代選擇器是通過父控件(直接或間接)子控件來篩選控件,前面的代碼里主界面和box1,box1和label1之間都是直接包含的,而主界面和label1是間接包含的關系。

例如我們想把box2里的標簽設置個背景色,要怎么做?

首先給box2設置好objectname

box2.setObjectName('box2')

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

QWidget#box2 QLabel  {
        background-color:pink;
}

如果我們新建一個box3,一個label3放在box3里

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

因為box2是label3的間接父關系,索引上面的qss對label3也是生效的。

8.子選擇器是通過父控件的直接子控件來篩選控件的。語法是父控件后跟一個大於號>,還是上面那個帶box3的例子,qss文件是這樣的

QWidget#box2>QLabel  {
        background-color:pink;
}

這樣就只對box2里的QLabel控件生效,label3作為box的間接子控件是不變化的

9.子控件選擇器用來選擇一個復合控件上的子控件,語法是兩個冒號::

同一行中是有相同子控件的控件
QCheckBox,QRadioButton
QCombBox,
QSpinBox,QDateEdit,QTimeEdit,QDateTimeEdit
QSlider
QProgressBar
QScrollBar
QGroupBox
QTableView
等待
常用復合控件

 我們可以通過特定的控件選擇空間的子控件比如我們創建個checkbox控件,把復選框的框框可以改下樣式(加了個圖片)

QCheckBox::indicator {
    image:url(../open.png);
    width:20px;
    height:20px;

}

看下效果

但是會發現用鼠標點擊是不是沒效果了,如果改這種效果,我們就需要用到下一節的內容:qss偽裝態,我們后面再講。

10補充

  上面講的各種選擇器是可以疊加使用的,用逗號分隔就可以了

QWidget#btn1,#btn2  {
        background-color:pink;
}

五.QSS偽裝態

  我們在上面一節第9條提到了偽裝態這個概念,他是限制控制只能在某種狀態下,被樣式表作用,語法是冒號:后面加關鍵字

選擇器:偽裝態

下面是常見的偽裝態

:checked    button部件被選中
:unchecked    button部件未被選中
:disabled    部件被禁用
:enabled    部件被啟用
:focus    部件獲得焦點
:hover    鼠標位於部件上
:pressed    部件被鼠標按下
:indeterminate    checkbox或radiobutton被部分選中
:off    部件可以切換,且處於off狀態
:on    部件可以切換,且處於on狀態
常見的偽裝態

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

1.不同的控件會有某種特定的狀態,具體的要看官方文檔

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

3可以連接使用:

:hover:checked 表明鼠標指向並且選中時
:hover:!checked鼠標經過但沒有選中

六.QSS聲明

  QSS聲明指明了控件會作用什么樣的樣式,以類似於字典的形式存在(分號分隔,而字典是逗號)

{
  key:value; key:value; }

   一般控件都符合名字叫做盒子模型的布局樣式,我們先看看這個樣式的概念

其中margin——外邊框

       border——內邊框

  content——內容

一個控件的尺寸定義好以后,就是上面圖中虛線的尺寸,而定義了外邊距‘、邊框和內邊距以后內容矩形是不停的被壓縮的,整體的尺寸是不會變的

1.邊框相關

針對邊框來說也有三個參數:樣式,寬度,顏色。而每個參數的設定可以一次設定四個參數(上右下左,以空格分割),也可以獨自設置

QLabel {
        background-color:yellow;
        border-width:5px;
        border-right-style:dotted;
      }

上面的代碼就是同時設置四個方向的邊框樣式

下面的就是樣式的代碼

none :  無邊框。與任何指定的border-width值無關
hidden :  隱藏邊框。IE不支持
dotted :  在MAC平台上IE4+與WINDOWS和UNIX平台上IE5.5+為點線。否則為實線(常用)
dashed :  在MAC平台上IE4+與WINDOWS和UNIX平台上IE5.5+為虛線。否則為實線(常用)
solid :  實線邊框(常用)
double :  雙線邊框。兩條單線與其間隔的和等於指定的border-width值
groove :  根據border-color的值畫3D凹槽
ridge :  根據border-color的值畫菱形邊框
inset :  根據border-color的值畫3D凹邊
outset :  根據border-color的值畫3D凸邊

 而如果想獨立設置,也可以分別按下面的方法指定

border-top-style
border-right-style
border-bottom-style
border-left-style

而寬度的設定也可以直接指定,也可以指定邊框

border-top-width
border-right-width
border-bottom-width
border-left-width

這里還有個要點,px(像素值) 和em(相對長度單位)

其中還有個換算單位

1em=16px

 最后的顏色和前面的都一樣,可以統一設置也可以獨立設置,但是還有一點,除了直接指定顏色還可以直接指定rgb的值

QLabel{
    border-left-color:reb(255,255,0)
          }

當然也可以設置16進制的值

#00ff00

最后看一下漸變色的設定。

 a.線性漸變

線性漸變的思路是按下面的坐標系變化的

 在定義坐標的時候,我們通常把x1,y1的值定為0,x2和y2的值定成1,然后可以指定好中間的顏色就可以了

QLabel {
        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);

      }

比方上面的qss文件,出來的效果就是這樣的從0到1中間分了0.4和0.8兩個點,顏色定義了會和橙色。

這里有個隱藏用法:如果我們定義了x2或y2的值為0就成了垂直或水平漸變色的效果

b.輻射漸變

輻射漸變的思路是這樣的

其中XcYc是圓心的坐標點,r為漸變的半徑,XfYf為焦距點(可以以為是顏色最濃的地方)

QLabel {
        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);

      }

出來的效果

如果我們把cxcy都設為0.5,則是從中間開始變色的

c.角度漸變

角度漸變是先確認個中心點(Xc,Yc),再確定出起始角度(0度為水平向右,逆時針旋轉),然后圍着原點轉一圈開始漸變

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

      } 

然后我們在看一看邊框圓角

因為默認情況控件的邊框顯示的都是矩形,但有些時候我們希望把空間的角變成圓弧,那有什么參數呢?

從上面的圖可以看出來,我們以不同的半徑畫控件邊框的內切圓,由於是內切,三個圓的圓心都在角平分線上,要想要不同的弧度,只需指定好半徑即可(也可以指定角設定)

border-radius
border-top-left-radius
border-top-right-radius
border-bottom-right-radius
border-bottom-left-radius

如果把半徑設為控件的一般,效果就是圓了。

QLabel {
        border-style:groove;
        border-width:22px;
        border-radius:150px

      } 

因為label的尺寸為300*300,我們把半徑設成150出來的效果就是圓形了

邊框圖片

 然而有些時候邊框效果不太容易通過效果設置,比如這個效果

那么我們就可以直接設定邊框圖片

QLabel {
        background-color:yellow;
        border-image:url(無標題.png);
      } 

但是要注意一下qss里是有個背景色的,由於圖片背景不是透明的,就會把背景色遮蓋

還有一點,如果設置的圖片如果尺寸比較小的話填滿控件后是會被拉伸的,例如我們把下面的圖片(20*20像素),添加在上面的label控件里結果就是被拉伸了

然后我們可以定義一個裁剪值和重復策略,意義是這樣的:

裁剪值:上——距離上邊的線(像素值)

    下——距離下邊的線(像素值)

    左——距離左邊的線(像素值)

    右——距離右邊的線(像素值)

重復  :round——平鋪

     repeat——重復

       stretch——拉伸

我們來結合一個圖來看吧

我們用上面定義的分割線把一副圖分割成了9份,然后四個角上的圖是不會被拉伸的,剩下的2,4,6,8是會按照定義的拉伸策略被拉伸。這個沒有比較好的例子就不演示了。

QLabel {
        background-color:yellow;
        border-image:url(無標題.png)30px 30px 30px 30px round;
        border-width:35px
      } 

2.外邊距(Margin)

外邊距和前面說的一樣,可以統一設置也可以分開設置

統一設置
margin (可以定義不同值,上、右、下、左)
分開設置 margin-top margin-right margin-bottom margin-left
QLabel {
        background-color:yellow;
        
        border-style:solid;
        border-width:10px;
        margin:20px 40px 80px 160px
      } 

可以看出來控件已經被截成矩形的了

3.內邊距

內邊距限制了控件內容顯示的區域范圍,設置的方法和上面的外邊距是一樣的

統一設置
padding (可以定義不同值,上、右、下、左)
分開設置
padding-top
padding-right
padding-bottom
padding-left

4.背景

背景(background)分下面幾條

background
background-color      #顏色
background-image      #圖片
background-repeat     #重復
background-position   #位置
background-origin
background-clip
background-attachment

我們一點點來搞清楚

a.background-color是沒什么好講的,可以直接加顏色,也可以加個rgb定義顏色

b.圖片和下面幾個可以一起來講,比方我們設定了個背景圖片

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

效果如下:

是不是都重復了,這時候就需要用到重復的定義了(默認情況是xy軸方向都重復的)

background-repeat:no-repeat   #只顯示一張(默認位置在左上角)
repeat-x                      #只重復x軸方向
repeat-y             #只重復y軸方向
repeat-xy             #重復xy軸兩個方向

因為如果我們用不重復的時候圖片顯示的位置是左上角(為了直觀我們加一個背景色來表明控件的位置和外觀)

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

顯示效果:

如果我們想要改變圖片的位置就可以通過下面的方法

background-position: 
right
top
bottom
left
middle

用下面的qss代碼設置

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

出來的效果

注意看紅框框,因為我們設置的是背景,是不會遮蓋前面層的文本的。

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

background-origin:
border
padding   #默認值
content

 我們把邊框顯示出來以后加上上面的圖

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

可以看出來,圖片是貼着邊框內部的

 

最后一個

background-attachment:
scroll
fixed

表示背景是否跟隨控件多余的部分滾動而滾動。如果我們的控件是一個可以滾動的控件(類似於QTextEdit)默認的scroll是背景隨着控件的滾動而滾動的

5.字體設置和前景色

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

#統一設置
font
#獨立設置
font-family
font-size
font-style
font-weight

其中字體形式分下面幾種

font-style:
normal    
italic            #斜體
oblique        #傾斜

而字體的粗細除了可以用下面的單詞表示,也可以直接定義數值

font-weight:
bold    #粗體
bolder  #更粗
lighter  #更細
100
200
300
400
。
。
。
由粗到細,400為normal,700等同於bold

還可以直接指定前景色

color

因為大部分的控件前景都為字符,設置了前景色就相當於改變了字符的顏色

看一下效果

QLabel {font-family:隸書;
font-size:30px;
font-style:oblique;
font-weight:bold;
color:red
}

效果圖就不放了,自己腦補一個紅色的Label字符串好了。

6.最大最小

最大最小和直接調用設置最大最小尺寸的方法一樣

min-width:
max-width:
min-height:
max-height:

7.子控件控制

整體來看子控件控制Subcontrol有下面幾種模式

Subcontrol-Origin
Subcontrol-Position
還可以細微調整
Top Bottom
Left Right

我們用一個spinbox來演示上面的效果

from PyQt5.Qt import *
import sys
class Window(QWidget):
        def __init__(self):
                super().__init__()
                self.UI_test()
                


        def UI_test(self):
                spin = QSpinBox(self)
                spin.resize(300,300)
                spin.move(50,50)
        
                spin.setStyleSheet("""
                
 
                """)


if __name__ == '__main__':
        app = QApplication(sys.argv)
        window = Window()
        window.show()
        sys.exit(app.exec_())

然后我們通過改變qss代碼來改變他的效果,正常情況

QSpinBox {
        font-size:20px;
        color:red;
        border:10px double green;
        border-radius:10px
} 

效果如下

因為上下按鈕是屬於前景的,在改變了前景色的時候箭頭的顏色也變了。

如果我們想改變上箭頭的效果可以使用前面講到的子控件選擇器

QSpinBox {
        font-size:20px;
        color:red;
        border:10px double green;
        border-radius:10px
}      
QSpinBox::up-button{
        width:50px;
        height:50px;
}

效果:

那我們想改變一下他們的位置就要用到這里的子控件控制了

QSpinBox {
        font-size:20px;
        color:red;
        border:10px double green;
        border-radius:10px
}      
QSpinBox::up-button{
        width:50px;
        height:50px;
        subcontrol-position:left middle
}
QSpinBox::down-button{
        width:50px;
        height:50px;
        subcontrol-position:right middle       
}

效果:

而這一節說的微調主要是和偽裝態聯系用的,比方鼠標指向后bottom 10px意思就是鼠標指向控件后控件向下移動10個像素(這里還有個設定的東西,position:relative或者position:absolute),其中relative是相對原先控件的位置變化的像素值,而absolute就結合了origin的位置了。

QSpinBox::down-button:hover {
        position:absolute;
        top:100px;
        width:50px;
        height:50px;
        subcontrol-position:right middle       
}

上面就是語法結構的參考形式。

上面講的就是qss語法的基本結構,具體的偽裝態,子控件形式什么的可以看下Qt的官方文檔

七.注意事項

1.級聯:

  QSS可以在QApplication、父控件、子控件中設置,這個我們在上面已經說過了。而一個控件的最終樣式,會收到父控件以及QApplication的影響。

2.沖突

  如果一個控件作為后代控件,被多個控件影響,則會不同屬性相互疊加,相同屬相產生覆蓋。這里還要考慮到特異性:同時設置的話要看那個優先級比較高:比如下面兩個按鈕

btn = QPushButton('b1',self)
btn2 = QPushButton('b2',self)
btn2.move(100,0)
btn2.setObjectName('btn2')


self.setStyleSheet("""

QPushButton {
        background-color:red
}

QPushButton#btn2 {
        background-color:green
}                           
                """)

由於btn2是有特異性的,所以優先級比較高。出來的效果就是btn1為紅色,btn2為綠色。

而如果一樣的特異性,那就取最后一個。

八.三方包

有些時候我們可以通過導入三方包來使用別人已經做好的qss代碼,這里我在命令行可以安裝一個包

pip install qdarkgraystyle

然后在最后就可以直接使用(這里就放出來最后一段的代碼)

if __name__ == '__main__':
app = QApplication(sys.argv)
import qdarkgraystyle
app.setStyleSheet(qdarkgraystyle.load_stylesheet_pyqt5())
window = Window()
window.show()
sys.exit(app.exec_())

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM