網(wǎng)站icp備案號(hào)怎么查詢/搜索引擎優(yōu)化實(shí)訓(xùn)報(bào)告
什么是QSS
QSS稱為Qt Style Sheets也就是Qt樣式表,它是Qt提供的一種用來自定義控件外觀的機(jī)制。QSS大量參考了CSS的內(nèi)容,只不過QSS的功能比CSS要弱很多,體現(xiàn)在選擇器要少,可以使用的QSS屬性也要少很多,并且并不是所有的屬性都可以用在Qt的所有控件上。
QSS在Qt程序中的使用辦法
首先將QSS寫在文件中,然后利用如下的代碼設(shè)置QSS:
MainWidget::MainWidget(QWidget *parent) :QWidget(parent),ui(new Ui::MainWidget)
{//應(yīng)用樣式 apply the qss styleQFile file(":/qss/main.qss");file.open(QFile::ReadOnly);QTextStream filetext(&file);QString stylesheet = filetext.readAll();this->setStyleSheet(stylesheet);file.close();
}
該段代碼寫在ui界面的后臺(tái)cpp文件的構(gòu)造函數(shù)中,主要是this->setStyleSheet()函數(shù)的設(shè)置功能,要說明的是該函數(shù)除了可以對(duì)整個(gè)當(dāng)前構(gòu)造數(shù)所在的那個(gè)類所表示的ui進(jìn)行整體應(yīng)用樣式以外,setStyleSheet()函數(shù)本身是QWidget的成員函數(shù),幾乎Qt中的大多數(shù)控件都可以直接使用該函數(shù)分別設(shè)置自己的樣式。
QSS的語(yǔ)法規(guī)則
QSS的語(yǔ)法規(guī)則幾乎與CSS相同。一條QSS的樣式是由兩部分組成的,一部分是選擇器指定了哪些控件會(huì)受到影響,另一部分是指定了屬性的值,表示這些控件的哪些屬性會(huì)受到影響。例如:
QPushButton { color: red }
QPushButton表示選擇器,指定了所有的QPushButton或者是QPushButton的子類會(huì)受到影響,注意凡是繼承自QPushButton的子類也會(huì)受到影響,這是與CSS中不同的地方,因?yàn)镃SS應(yīng)用的都是一些標(biāo)簽,沒有類的層次結(jié)構(gòu),更加沒有子類的概念。而后面的{color:red}則是規(guī)則的定義,表明指定前景顏色是紅色。整個(gè)意思就是設(shè)置QPushButton類以及其子類的所有實(shí)例的前景色是紅色。
如果MyButton繼承自QPushButton,那么上面的規(guī)則也會(huì)應(yīng)用到所有MyButton控件上,但是如果規(guī)則是如下的:
MyButton{color:red}
則只會(huì)對(duì)MyButton的實(shí)例應(yīng)用紅色的前景顏色,而對(duì)QPushButton的實(shí)例沒有應(yīng)用。
QSS的選擇器類型
1.通配選擇器:* ; 匹配所有的控件
2.類型選擇器:QPushButton ; 匹配所有QPushButton和其子類的實(shí)例
3.屬性選擇器:QPushButton[flat=“false”]; 匹配所有flat屬性是false的QPushButton實(shí)例,注意該屬性可以是自定義的屬性,不一定非要是類本身具有的屬性
4.類選擇器: .QPushButton ; 匹配所有QPushButton的實(shí)例,但是并不匹配其子類。這是與CSS中的類選擇器不一樣的地方,注意前面有一個(gè)點(diǎn)號(hào)
5.ID選擇器: #myButton; 匹配所有id為myButton的控件實(shí)例,這里的id實(shí)際上就是objectName指定的值
6.后代選擇器: QDialog QPushButton ; 所有QDialog容器中包含的QPushButton,不管是直接的還是間接的
7.子選擇器: QDialog > QPushButton; 所有QDialog容器下面的QPushButton,其中要求QPushButton的直接父容器是QDialog
另外上面所有的這些選擇器可以聯(lián)合使用,并且支持一次設(shè)置多個(gè)選擇器類型,用逗號(hào)隔開,這點(diǎn)與CSS一樣,例如#frameCut,#frameInterrupt,#frameJoin 表示所有這些id使用一個(gè)規(guī)則。#mytable QPushButton 表示選擇所有id為mytable的容器下面的QPushButton實(shí)例
QSS子控件
QSS的子控件實(shí)際上也是選擇器的一種,因?yàn)檫@種選擇器與CSS有一些不同,所以單獨(dú)拿出來說,QSS的子控件選擇器是應(yīng)用在一些復(fù)合控件上的,典型的例如QComboBox,該控件的外觀包含幾個(gè)部分,一般情況下有一個(gè)矩形的外邊框,右邊有一個(gè)向下的箭頭用于提示點(diǎn)擊之后會(huì)有彈出下拉列表。例如:
QComboBox::drop-down { image: url(dropdown.png) }
上面的樣式指定所有QComboBox的下拉箭頭的圖片為自定義的圖片dropdown.png
::dropdown子控件選擇器也可以與上面提到的選擇器一起聯(lián)合使用:
QComboBox#myQComboBox::drop-down { image: url(dropdown.png) }
指定id名為myQComboBox的QComboBox控件的下拉箭頭的自定義圖片,要注意的是子控件選擇器實(shí)際上是選擇復(fù)合控件中的一部分,也就是說對(duì)復(fù)合控件中的一部分應(yīng)用樣式,例如為QComboBox的下拉箭頭指定圖片,而不是為QComboBox本身指定圖片。
QSS為很多復(fù)雜的復(fù)合控件提供了子控件的定義,以方便對(duì)這些復(fù)合控件的各個(gè)部分進(jìn)行樣式設(shè)置。限于篇幅,本文也不能將這些可用的子控件都列出來,在安裝QtCreator之后自帶的幫助中就有很詳細(xì)的描述。
QSS偽狀態(tài)
QSS的偽狀態(tài)選擇器實(shí)際上與CSS中的類似,是以冒號(hào)開頭的一個(gè)選擇表達(dá)式,例如:hover表示當(dāng)鼠標(biāo)經(jīng)過時(shí)候的狀態(tài)。他限制了當(dāng)控件在某一種狀態(tài)下的時(shí)候才能應(yīng)用QSS規(guī)則,偽狀態(tài)只能描述一個(gè)控件的狀態(tài),或者是一個(gè)復(fù)合控件中的子控件的狀態(tài),所以該偽狀態(tài)選擇器只能放在選擇器的最后面,例如:
QComboBox:hover{background-color:red;}
該規(guī)則表示當(dāng)鼠標(biāo)經(jīng)過QComboBox上面的時(shí)候,其背景顏色指定為紅色,該偽狀態(tài) :hover描述的是QComboBox的狀態(tài)。
偽狀態(tài)除了描述選擇器選擇的控件以外,還可以描述子控件選擇器所選擇的復(fù)合控件中的子控件的狀態(tài),例如
QComboBox::drop-down:hover{background-color:red;}
表示當(dāng)鼠標(biāo)經(jīng)過QComboBox的下拉箭頭的時(shí)候,該下拉箭頭的背景顏色變成紅色。
此外偽狀態(tài)可以用一個(gè)感嘆號(hào)表示否,例如:hover表示鼠標(biāo)經(jīng)過,而:!hover表示鼠標(biāo)沒有經(jīng)過的狀態(tài)。幾個(gè)偽狀態(tài)可以同時(shí)一起使用,例如:
QCheckBox:hover:checked { color: white }
指定一個(gè)當(dāng)鼠標(biāo)經(jīng)過一個(gè)選中的QCheckBox的時(shí)候,設(shè)置其文字的前景顏色為白色。
QSS提供了很多的偽狀態(tài),一些偽狀態(tài)只能用在特定的控件上,具體有哪些偽狀態(tài),在Qt的幫助里面有詳細(xì)的列表,限于篇幅這里也不列出了。
QSS級(jí)聯(lián)與沖突
QSS中的級(jí)聯(lián)包含幾個(gè)方面的概念,一個(gè)是當(dāng)在同一個(gè)控件上應(yīng)用兩個(gè)不同的規(guī)則,那么應(yīng)該應(yīng)用哪一個(gè)規(guī)則的問題,也就是如何解決這種沖突。二個(gè)是在一個(gè)容器控件上設(shè)置的QSS規(guī)則會(huì)對(duì)容器里面的控件產(chǎn)生效果(這要取決于容器控件上設(shè)置的QSS規(guī)則是什么樣的規(guī)則,如果容器控件上設(shè)置的QSS規(guī)則僅僅針對(duì)容器控件本身則該規(guī)則對(duì)子控件沒有影響,如果該QSS規(guī)則里面有對(duì)子控件的設(shè)置,則自然會(huì)對(duì)子控件產(chǎn)生效果),級(jí)聯(lián)問題是解決當(dāng)一個(gè)控件被層層父容器包裹,并且在每一層的父容器上都有對(duì)該控件的樣式設(shè)置的時(shí)候,該控件的最終效果是合并這些父容器上的QSS效果。
沖突問題:
QPushButton#okButton { color: gray }
QPushButton { color: red }
這兩條規(guī)則都會(huì)應(yīng)用到名為okButton的按鈕上,但是他們?yōu)橥粋€(gè)屬性設(shè)置了不同的顏色,這會(huì)有沖突,那么要解決這樣的沖突就必須考慮到選擇器的特異性(這個(gè)詞怎么理解,我理解為這個(gè)特異性為更加特殊,實(shí)際上CSS上用權(quán)重表示這里的特異性),顯然QPushButton#okButton僅僅針對(duì)對(duì)象名為okButton的控件有效果,而QPushButton卻對(duì)所有的QPushButton的實(shí)例或者是其子類的實(shí)例有效果,顯然QPushButton#okButton選擇器更加特殊,也就是更具有特異性。所以最終okButton前景色被應(yīng)用為灰色。如果兩條規(guī)則的特異性一樣,那么就選擇放在后面的那一條。
另外如果一個(gè)選擇器應(yīng)用了偽狀態(tài),而另一個(gè)沒有,那么應(yīng)用了偽狀態(tài)的選擇器要更加特殊,例如:
QPushButton:hover { color: white }
QPushButton { color: red }
顯然QPushButton:hover比單純的QPushButton更加具有特異性。這兩條規(guī)則表示當(dāng)鼠標(biāo)放在按鈕上的時(shí)候文字是白色,其他情況下都是紅色。
如下面兩個(gè)規(guī)則的特異性是一樣的,那么應(yīng)該是如何應(yīng)用呢:
QPushButton:hover { color: white } //如果鼠標(biāo)經(jīng)過則前景白色
QPushButton:enabled { color: red } //如果按鈕是enabled狀態(tài)則前景紅色
所以默認(rèn)情況下前景文字是紅色的,當(dāng)鼠標(biāo)經(jīng)過的時(shí)候并不會(huì)變成白色,因?yàn)樗麄兊奶禺愋允且粯拥?#xff0c;所以選擇后面的,也就是紅色。
那么換一下順序會(huì)怎樣呢:
QPushButton:enabled { color: red } //如果按鈕是enabled狀態(tài)則前景紅色
QPushButton:hover { color: white } //如果鼠標(biāo)經(jīng)過則前景白色
當(dāng)鼠標(biāo)經(jīng)過的時(shí)候,就變成白色的了,因?yàn)樗麄兊奶禺愋砸粯?#xff0c;所以選擇后面的規(guī)則,也就是鼠標(biāo)經(jīng)過前景變成白色。
如果把其中的一條的特異性增加,例如:
QPushButton:hover:enabled { color: white }
QPushButton:enabled { color: red }
那么第一條的特異性比第二條大,所以應(yīng)用第一條的規(guī)則。
另外一種特異性發(fā)生在類型選擇器上:
QPushButton { color: red } //應(yīng)用在所有的QPushButton上
QAbstractButton { color: gray } //應(yīng)用在所有的QAbstractButton上
而在類的繼承結(jié)構(gòu)上,QAbstractButton是QPushButton的父類,顯然QPushButton更加具有特異性,所以QPushButton的前景顏色被應(yīng)用為紅色,而不是灰色。有沒有一個(gè)辦法來確定兩條QSS規(guī)則的特異性大小呢,其實(shí)QSS使用的特異性的計(jì)算方法與CSS是一樣的,詳細(xì)可以參考CSS2的文檔規(guī)范,這里還是簡(jiǎn)要的說明一下,特異性這個(gè)東西在CSS中一般被稱為權(quán)重,權(quán)重越大的越優(yōu)先使用,CSS的計(jì)算規(guī)則如下:
1.計(jì)算一條規(guī)則中id選擇器的個(gè)數(shù),假設(shè)存放在變量a中
2.計(jì)算一條規(guī)則中類選擇器和屬性選擇器的個(gè)數(shù),存放在變量b中
3.計(jì)算一條規(guī)則中的類型選擇器的個(gè)數(shù),存放在變量c中
4.忽略偽元素,對(duì)應(yīng)QSS中的子控件
下面是具體的計(jì)算方法:
* {} /* 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 */
上面的計(jì)算規(guī)則是CSS的計(jì)算規(guī)則,同樣可以應(yīng)用的QSS上。
關(guān)于級(jí)聯(lián):
QSS可以設(shè)置在QApplication上,也可以設(shè)置在一個(gè)部件的容器部件上,也可以設(shè)置在子孫部件上,一個(gè)部件最終使用的樣式效果是合并了他的所有父容器,祖父容器等上面設(shè)置的所有樣式的結(jié)果,這些設(shè)置會(huì)進(jìn)行疊加。如果在級(jí)聯(lián)過程中發(fā)生了沖突,例如部件本身指定的前景顏色為綠色,而其父親容器為其指定的前景顏色為紅色,此時(shí)就選擇部件本身設(shè)置的樣式效果。例如:
qApplication->setStyleSheet("QPushButton { color: white }");
myPushButton->setStyleSheet("* { color: blue }");
第一條語(yǔ)句表示在QApplication上設(shè)置QPushButton的樣式,而第二條語(yǔ)句表示在myPushButton對(duì)象上設(shè)置樣式。最終結(jié)果會(huì)將myPushButton的前景顏色設(shè)置為藍(lán)色。級(jí)聯(lián)效果主要應(yīng)用在當(dāng)一個(gè)控件的樣式在多個(gè)容器控件上都有設(shè)置的時(shí)候,該控件的最終效果是這些所有容器控件上效果的合并。級(jí)聯(lián)規(guī)則在CSS中本身也是一個(gè)復(fù)雜的主題,如果大家感興趣,還是需要自己參考CSS2的規(guī)范文檔,本節(jié)僅僅是拋裝引玉。
另外一個(gè)要提到的是,QSS中似乎為父容器控件本身設(shè)置的樣式,并不會(huì)被子控件繼承,例如如果QFrame中有一個(gè)QPushButton控件,那么如下的語(yǔ)句:
ui->frame->setStyleSheet("QFrame{ color: red; border:1px solid red }");
該語(yǔ)句僅僅為QFrame設(shè)置前景顏色以及邊框的效果并不會(huì)應(yīng)用到其里面的QPushButton上,如果是下面的語(yǔ)句則都可以:
ui->frame->setStyleSheet("QPushButton{ color: red; border:1px solid red }");
ui->frame->setStyleSheet("*{ color: red; border:1px solid red }");
QSS實(shí)際應(yīng)用中要注意的地方
在使用QSS的時(shí)候遇到過一些坑,看似簡(jiǎn)單,但是如果不知道的話,還是很折磨人的:
<1>使用QSS設(shè)置邊框無效,例如:
border:1px solid red; //Ok
border:solid 1px red; //Error
border:red 1px solid; //Error
border:red solid 1px; //Error
設(shè)置邊框顏色和像素的時(shí)候,必須是第一種順序,而CSS中是無所謂的,至于原因,我也不清楚,就是這么坑人。
<2> QSS設(shè)置寬高無效:
在QSS中設(shè)置寬高必須要使用 min-width和min-height,max-width,max-height來設(shè)置,用width和height設(shè)置是沒有任何效果的。
<3>QComboBox的樣式設(shè)置的問題:
QcomboBox是一個(gè)復(fù)雜的控件,QComboBox由3部分組成,一個(gè)是QComboBox的外框,里面有一個(gè)下拉按鈕,這個(gè)按鈕可以通過QComboBox::drop-down 來控制其位置,將其定義到QComboBox的左邊而不一定是右邊。另外在這個(gè)下拉按鈕上面一般會(huì)有一個(gè)向下的箭頭,這個(gè)箭頭圖像也是可以定制的,通過QComboBox::down-arrow來指定箭頭的圖像。
如果要控制QComboBox的彈出下拉列表的樣式需要通過:
QComboBox QAbstractItemView {//設(shè)置當(dāng)點(diǎn)擊下拉按鈕之后彈出的下拉列表的樣式,要注意的是這里的樣式//僅僅只能設(shè)置彈出的整個(gè)下拉列表范圍的矩形的樣式,不能設(shè)置下拉列表//中的每一個(gè)下拉項(xiàng)的樣式,例如不能設(shè)置每一個(gè)下拉項(xiàng)高度
}
QcomboBox{//設(shè)置未彈出下拉列表的樣式
}QComboBox QAbstractItemView::item {
//設(shè)置彈出下拉列表中的每一個(gè)下拉項(xiàng)的樣式,這里的樣式要想生效,必須先
//對(duì)QcomboBox做下面的設(shè)置
//QStyledItemDelegate* itemDelegate = new QStyledItemDelegate();
//combox->setItemDelegate(itemDelegate);
}