QSS總結以及最近做的Qt專案

薰衣草的旋律發表於2015-11-13

什麼是QSS

QSS稱為Qt Style Sheets也就是Qt樣式表,它是Qt提供的一種用來自定義控制元件外觀的機制。QSS大量參考了CSS的內容,只不過QSS的功能比CSS要弱很多,體現在選擇器要少,可以使用的QSS屬性也要少很多,並且並不是所有的屬性都可以用在Qt的所有控制元件上。

QSS在Qt程式中的使用辦法

首先將QSS寫在檔案中,然後利用如下的程式碼設定QSS:

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWidget)
{
  //應用樣式 apply the qss style
    QFile file(":/qss/main.qss");
    file.open(QFile::ReadOnly);
    QTextStream filetext(&file);
    QString stylesheet = filetext.readAll();
    this->setStyleSheet(stylesheet);
   file.close();
}

該段程式碼寫在ui介面的後臺cpp檔案的建構函式中,主要是this->setStyleSheet()函式的設定功能,要說明的是該函式除了可以對整個當前構造數所在的那個類所表示的ui進行整體應用樣式以外,setStyleSheet()函式本身是QWidget的成員函式,幾乎Qt中的大多數控制元件都可以直接使用該函式分別設定自己的樣式。

QSS的語法規則

QSS的語法規則幾乎與CSS相同。一條QSS的樣式是由兩部分組成的,一部分是選擇器指定了哪些控制元件會受到影響,另一部分是指定了屬性的值,表示這些控制元件的哪些屬性會受到影響。例如:

QPushButton { color: red }

QPushButton表示選擇器,指定了所有的QPushButton或者是QPushButton的子類會受到影響,注意凡是繼承自QPushButton的子類也會受到影響,這是與CSS中不同的地方,因為CSS應用的都是一些標籤,沒有類的層次結構,更加沒有子類的概念。而後面的{color:red}則是規則的定義,表明指定前景顏色是紅色。整個意思就是設定QPushButton類以及其子類的所有例項的前景色是紅色。

如果MyButton繼承自QPushButton,那麼上面的規則也會應用到所有MyButton控制元件上,但是如果規則是如下的:

MyButton{color:red} 

則只會對MyButton的例項應用紅色的前景顏色,而對QPushButton的例項沒有應用。

QSS的選擇器型別

1.通配選擇器:*  ; 匹配所有的控制元件
2.型別選擇器:QPushButton ; 匹配所有QPushButton和其子類的例項
3.屬性選擇器:QPushButton[flat="false"]; 匹配所有flat屬性是false的QPushButton例項,注意該屬性可以是自定義的屬性,不一定非要是類本身具有的屬性
4.類選擇器:  .QPushButton ;  匹配所有QPushButton的例項,但是並不匹配其子類。這是與CSS中的類選擇器不一樣的地方,注意前面有一個點號
5.ID選擇器:  #myButton; 匹配所有id為myButton的控制元件例項,這裡的id實際上就是objectName指定的值
6.後代選擇器: QDialog QPushButton ; 所有QDialog容器中包含的QPushButton,不管是直接的還是間接的
7.子選擇器:  QDialog > QPushButton; 所有QDialog容器下面的QPushButton,其中要求QPushButton的直接父容器是QDialog

另外上面所有的這些選擇器可以聯合使用,並且支援一次設定多個選擇器型別,用逗號隔開,這點與CSS一樣,例如#frameCut,#frameInterrupt,#frameJoin 表示所有這些id使用一個規則。#mytable  QPushButton 表示選擇所有id為mytable的容器下面的QPushButton例項

QSS子控制元件

QSS的子控制元件實際上也是選擇器的一種,因為這種選擇器與CSS有一些不同,所以單獨拿出來說,QSS的子控制元件選擇器是應用在一些複合控制元件上的,典型的例如QComboBox,該控制元件的外觀包含幾個部分,一般情況下有一個矩形的外邊框,右邊有一個向下的箭頭用於提示點選之後會有彈出下拉選單。例如:

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

上面的樣式指定所有QComboBox的下拉箭頭的圖片為自定義的圖片dropdown.png
::dropdown子控制元件選擇器也可以與上面提到的選擇器一起聯合使用:

QComboBox#myQComboBox::drop-down { image: url(dropdown.png) }

指定id名為myQComboBox的QComboBox控制元件的下拉箭頭的自定義圖片,要注意的是子控制元件選擇器實際上是選擇複合控制元件中的一部分,也就是說對複合控制元件中的一部分應用樣式,例如為QComboBox的下拉箭頭指定圖片,而不是為QComboBox本身指定圖片。

QSS為很多複雜的複合控制元件提供了子控制元件的定義,以方便對這些複合控制元件的各個部分進行樣式設定。限於篇幅,本文也不能將這些可用的子控制元件都列出來,在安裝QtCreator之後自帶的幫助中就有很詳細的描述。

QSS偽狀態

QSS的偽狀態選擇器實際上與CSS中的類似,是以冒號開頭的一個選擇表示式,例如:hover表示當滑鼠經過時候的狀態。他限制了當控制元件在某一種狀態下的時候才能應用QSS規則,偽狀態只能描述一個控制元件的狀態,或者是一個複合控制元件中的子控制元件的狀態,所以該偽狀態選擇器只能放在選擇器的最後面,例如:

QComboBox:hover{background-color:red;}

該規則表示當滑鼠經過QComboBox上面的時候,其背景顏色指定為紅色,該偽狀態 :hover描述的是QComboBox的狀態。
偽狀態除了描述選擇器選擇的控制元件以外,還可以描述子控制元件選擇器所選擇的複合控制元件中的子控制元件的狀態,例如:

QComboBox::drop-down:hover{background-color:red;}

表示當滑鼠經過QComboBox的下拉箭頭的時候,該下拉箭頭的背景顏色變成紅色。
此外偽狀態可以用一個感嘆號表示否,例如:hover表示滑鼠經過,而:!hover表示滑鼠沒有經過的狀態。幾個偽狀態可以同時一起使用,例如:

QCheckBox:hover:checked { color: white }

指定一個當滑鼠經過一個選中的QCheckBox的時候,設定其文字的前景顏色為白色。
QSS提供了很多的偽狀態,一些偽狀態只能用在特定的控制元件上,具體有哪些偽狀態,在Qt的幫助裡面有詳細的列表,限於篇幅這裡也不列出了。

QSS級聯與衝突

QSS中的級聯包含幾個方面的概念,一個是當在同一個控制元件上應用兩個不同的規則,那麼應該應用哪一個規則的問題,也就是如何解決這種衝突。二個是在一個容器控制元件上設定的QSS規則會對容器裡面的控制元件產生效果(這要取決於容器控制元件上設定的QSS規則是什麼樣的規則,如果容器控制元件上設定的QSS規則僅僅針對容器控制元件本身則該規則對子控制元件沒有影響,如果該QSS規則裡面有對子控制元件的設定,則自然會對子控制元件產生效果),級聯問題是解決當一個控制元件被層層父容器包裹,並且在每一層的父容器上都有對該控制元件的樣式設定的時候,該控制元件的最終效果是合併這些父容器上的QSS效果。

衝突問題:

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

這兩條規則都會應用到名為okButton的按鈕上,但是他們為同一個屬性設定了不同的顏色,這會有衝突,那麼要解決這樣的衝突就必須考慮到選擇器的特異性(這個詞怎麼理解,我理解為這個特異性為更加特殊,實際上CSS上用權重表示這裡的特異性),顯然QPushButton#okButton僅僅針對物件名為okButton的控制元件有效果,而QPushButton卻對所有的QPushButton的例項或者是其子類的例項有效果,顯然QPushButton#okButton選擇器更加特殊,也就是更具有特異性。所以最終okButton前景色被應用為灰色。如果兩條規則的特異性一樣,那麼就選擇放在後面的那一條。

另外如果一個選擇器應用了偽狀態,而另一個沒有,那麼應用了偽狀態的選擇器要更加特殊,例如:

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

顯然QPushButton:hover比單純的QPushButton更加具有特異性。這兩條規則表示當滑鼠放在按鈕上的時候文字是白色,其他情況下都是紅色。
如下面兩個規則的特異性是一樣的,那麼應該是如何應用呢:

QPushButton:hover { color: white }  //如果滑鼠經過則前景白色
QPushButton:enabled { color: red }  //如果按鈕是enabled狀態則前景紅色

所以預設情況下前景文字是紅色的,當滑鼠經過的時候並不會變成白色,因為他們的特異性是一樣的,所以選擇後面的,也就是紅色。
那麼換一下順序會怎樣呢:

QPushButton:enabled { color: red }  //如果按鈕是enabled狀態則前景紅色
QPushButton:hover { color: white }  //如果滑鼠經過則前景白色

當滑鼠經過的時候,就變成白色的了,因為他們的特異性一樣,所以選擇後面的規則,也就是滑鼠經過前景變成白色。
如果把其中的一條的特異性增加,例如:

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

那麼第一條的特異性比第二條大,所以應用第一條的規則。
另外一種特異性發生在型別選擇器上:

QPushButton { color: red }   //應用在所有的QPushButton上
QAbstractButton { color: gray } //應用在所有的QAbstractButton上

而在類的繼承結構上,QAbstractButton是QPushButton的父類,顯然QPushButton更加具有特異性,所以QPushButton的前景顏色被應用為紅色,而不是灰色。有沒有一個辦法來確定兩條QSS規則的特異性大小呢,其實QSS使用的特異性的計算方法與CSS是一樣的,詳細可以參考CSS2的文件規範,這裡還是簡要的說明一下,特異性這個東西在CSS中一般被稱為權重,權重越大的越優先使用,CSS的計算規則如下:

1.計算一條規則中id選擇器的個數,假設存放在變數a中
2.計算一條規則中類選擇器和屬性選擇器的個數,存放在變數b中
3.計算一條規則中的型別選擇器的個數,存放在變數c中
4.忽略偽元素,對應QSS中的子控制元件

下面是具體的計算方法:

*             {}  /* 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 */

上面的計算規則是CSS的計算規則,同樣可以應用的QSS上。

關於級聯:


QSS可以設定在QApplication上,也可以設定在一個部件的容器部件上,也可以設定在子孫部件上,一個部件最終使用的樣式效果是合併了他的所有父容器,祖父容器等上面設定的所有樣式的結果,這些設定會進行疊加。如果在級聯過程中發生了衝突,例如部件本身指定的前景顏色為綠色,而其父親容器為其指定的前景顏色為紅色,此時就選擇部件本身設定的樣式效果。例如:

qApplication->setStyleSheet("QPushButton { color: white }");
myPushButton->setStyleSheet("* { color: blue }");

第一條語句表示在QApplication上設定QPushButton的樣式,而第二條語句表示在myPushButton物件上設定樣式。最終結果會將myPushButton的前景顏色設定為藍色。級聯效果主要應用在當一個控制元件的樣式在多個容器控制元件上都有設定的時候,該控制元件的最終效果是這些所有容器控制元件上效果的合併。級聯規則在CSS中本身也是一個複雜的主題,如果大家感興趣,還是需要自己參考CSS2的規範文件,本節僅僅是拋裝引玉。


另外一個要提到的是,QSS中似乎為父容器控制元件本身設定的樣式,並不會被子控制元件繼承,例如如果QFrame中有一個QPushButton控制元件,那麼如下的語句:

ui->frame->setStyleSheet("QFrame{ color: red; border:1px solid red }");

該語句僅僅為QFrame設定前景顏色以及邊框的效果並不會應用到其裡面的QPushButton上,如果是下面的語句則都可以:

ui->frame->setStyleSheet("QPushButton{ color: red; border:1px solid red }");
ui->frame->setStyleSheet("*{ color: red; border:1px solid red }");

QSS實際應用中要注意的地方

在使用QSS的時候遇到過一些坑,看似簡單,但是如果不知道的話,還是很折磨人的:
<1>使用QSS設定邊框無效,例如:

border:1px solid red; //Ok
border:solid 1px red; //Error
border:red 1px solid; //Error
border:red solid 1px; //Error

設定邊框顏色和畫素的時候,必須是第一種順序,而CSS中是無所謂的,至於原因,我也不清楚,就是這麼坑人。

<2> QSS設定寬高無效:
在QSS中設定寬高必須要使用 min-width和min-height,max-width,max-height來設定,用width和height設定是沒有任何效果的。

<3>QComboBox的樣式設定的問題:
QcomboBox是一個複雜的控制元件,QComboBox由3部分組成,一個是QComboBox的外框,裡面有一個下拉按鈕,這個按鈕可以通過QComboBox::drop-down 來控制其位置,將其定義到QComboBox的左邊而不一定是右邊。另外在這個下拉按鈕上面一般會有一個向下的箭頭,這個箭頭影象也是可以定製的,通過QComboBox::down-arrow來指定箭頭的影象。

如果要控制QComboBox的彈出下拉選單的樣式需要通過:

QComboBox QAbstractItemView {
  //設定當點選下拉按鈕之後彈出的下拉選單的樣式,要注意的是這裡的樣式
  //僅僅只能設定彈出的整個下拉選單範圍的矩形的樣式,不能設定下拉選單
  //中的每一個下拉項的樣式,例如不能設定每一個下拉項高度
}
QcomboBox{
  //設定未彈出下拉選單的樣式
}

QComboBox QAbstractItemView::item {
//設定彈出下拉選單中的每一個下拉項的樣式,這裡的樣式要想生效,必須先
//對QcomboBox做下面的設定
//QStyledItemDelegate* itemDelegate = new QStyledItemDelegate();
//combox->setItemDelegate(itemDelegate);    
}

Qt開發的程式的案例

前面一段時間用Qt開發了一個基於公司平臺的視訊匯出與編輯工具,當作一個案例貼出來吧,還是有很多可以美化的地方,窗體的外框沒有做任何美化處理,用QSS做起來其實還是蠻簡單的,裡面的頁面按鈕,文字框,分頁功能等都用QSS設定過,其實這個軟體的介面算是中規中矩的,要做成酷狗,360那種風格用QSS是完全沒有問題的:

1

登入介面,裡面用到了Qt提供的正則驗證功能,如果輸入的ip不符合規則,則根本輸入不了,例如如果輸入一個非法的字元,則文字框中沒有反應

登入進去之後的主介面,一共有7個選項卡,每一個選項卡代表一個功能:

視訊匯出:匯出web平臺上的視訊資料,包括檔案,片頭片尾,視訊的索引,可以匯出電影模式,資源模式,支援斷點續傳。
視訊剪下:可以將視訊中不需要的內容剪下掉
視訊擷取:擷取視訊中需要的部分
後期導播:對資源模式進行後期導播
建立片頭片尾:傻瓜式的生成片頭片尾的圖片檔案
合成片頭片尾:將片頭片尾的圖片檔案新增到一個視訊的起始和結束
轉碼上傳:將多種格式的視訊檔案轉碼成MP4檔案並上傳到web平臺

1

視訊匯出功能,實際上是匯出一個課件,該課件可能錄製的有電影模式的視訊,資源模式的視訊,或者都有。功能介紹如下:

1

視訊剪下對視訊進行剪下處理:

1

對視訊進行擷取:

1

對資源模式進行後期導播:

1

建立自定義片頭片尾(其實就是傻瓜式的讓使用者生成自定義圖片),裡面的文字可以拖動,可以鍵盤微調,可以修改:

1

合併片頭片尾,將生成好的片頭片尾圖片,合併到一個mp4的開始和結尾處,可以指定片頭片尾的圖片檔案,並指定在mp4開頭或結尾顯示的時間:

1

轉碼與上傳:

1

程式裡面的外觀包括,下拉選單,文字輸入框,按鈕,表格,tab等都是使用QSS設定的。QSS參考了CSS,所有裡面有一些屬性是與CSS相同的,但並不是所有的CSS屬性都能夠在QSS中使用,也並不是所有的Qt控制元件都支援CSS的盒模型,Qt幫助中關於QSS的部分詳細描述了可用的QSS屬性列表,以及控制元件列表,偽狀態列表,子控制元件列表,QSS中可用的圖示列表,以及QSS屬性值的單位列表,限於篇幅不可能將所有這些都詳細列出來,其實在安裝QtCreator之後的幫助文件中有詳細的描述,其列表類似下面的圖(描述了部分偽狀態的說明):

1

相關文章