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

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


免責聲明!

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



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