天天看點

QSS總結以及最近做的Qt項目

什麼是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是完全沒有問題的:

QSS總結以及最近做的Qt項目

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

登入進去之後的主界面,一共有7個頁籤,每一個頁籤代表一個功能:

視訊導出:導出web平台上的視訊資料,包括檔案,片頭片尾,視訊的索引,可以導出電影模式,資源模式,支援斷點續傳。

視訊剪切:可以将視訊中不需要的内容剪切掉

視訊截取:截取視訊中需要的部分

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

建立片頭片尾:傻瓜式的生成片頭片尾的圖檔檔案

合成片頭片尾:将片頭片尾的圖檔檔案添加到一個視訊的起始和結束

轉碼上傳:将多種格式的視訊檔案轉碼成MP4檔案并上傳到web平台

QSS總結以及最近做的Qt項目

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

QSS總結以及最近做的Qt項目

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

QSS總結以及最近做的Qt項目

對視訊進行截取:

QSS總結以及最近做的Qt項目

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

QSS總結以及最近做的Qt項目

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

QSS總結以及最近做的Qt項目

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

QSS總結以及最近做的Qt項目

轉碼與上傳:

QSS總結以及最近做的Qt項目

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

QSS總結以及最近做的Qt項目

繼續閱讀