學習Qss--選擇器

一、通用選擇器

通用選擇器又叫通配符選擇器;
格式

* { attribute: value; }

通用選擇器用(*)來表示,它表示匹配程序中所有的widget。
注意點:由於通用選擇器會匹配所有的widgets,效率較低,因此應該儘量減少或者不用
一般用法:通用選擇器一般用來給應用程序設置統一的字體,例如:

* { font: normal 20px “微軟雅黑”; }

這條語句表示將程序中所有widget的字體大小都設置爲20px大小,字體採用微軟雅黑。

二、類型選擇器

格式

className { attribute: value; }

類名即Widget類名,由QObject::metaObject()::className獲取,類型選擇器匹配所有該類以及該類的派生類的對象,例如:

QPushButton
{
	color: blue;
}

這條語句表示,程序中所有的QPushButton類和它的派生類的對象,它們的前景色(即文字顏色)被設置爲藍色。
注意點:Qt樣式表使用widget的QObject::className()來決定何時應用類型選擇器。當自定義控件在命令空間之中(或它是一個嵌套類),QObject::className()會返回(::),這與子控件選擇器相沖突,爲了解決這個問題,當爲命名空間中widget使用類型選擇器時,我們必須將"::“替換成”--",例如:

namespace ns 
{
	class MyPushButton : public QPushButton
	{
		//...
	}
}

//...
qApp->setStyleSheet("ns--MyPushButton {background: yellow; }");

一般用法:類型選擇器會匹配所有該類以及該類的派生類的對象,所以我們在程序中,有時爲了統一一些具有相似性的控件的樣式,可以使用類型選擇器,如,我們想要爲QSpinBox,QDoubleSpinBon,QDateTimeEdit,QDateEdit,QDataEdit等這些編輯框的控件設置一些相同的樣式,因爲它們都是QAbstractSpinBox類的派生類,因此可以如下寫:

QAbstractSpinBox
{
	min-height: 30px;
	max_height: 30px;
	border-width: 1px;
	rder-style: solid;
	order-color: gray;
	padding: 0px;
}

三、類選擇器

格式

.className {attribute: value; }

這裏的類名與類型選擇器中的類名一樣,不同的是,類選擇器的類名前面有一個(.),這種選擇器只會匹配該類的所有對象,而不會匹配其派生類的對象。例如:

.QPushButton
{
	color: blue;
}

一般用法:類選擇器提供了一種匹配該類的對象但不會匹配派生類的方法,通常用來特例化擁有派生類的類對象,但不僅限於此。例如在應用程序中,使用QFrame作爲容器widget,此時想要對它設置一些樣式,但又不想影響它的子類對象(QLable、QAbstractScrollArea等等),那麼就可以使用類選擇器給所有的QFrame設置相同的樣式,例如:

.QFrame
{
	padding: 15px 25px;
}

四、ID選擇器

格式

#ID { attribute: value; }

這裏的ID指的是objectName,每個QObject類及其派生類都有一個屬性,“#”+objectName構成了ID選擇器,它匹配所有objectName爲ID選擇器所指定的名稱的對象,爲其設置樣式,例如:

#button_1
{
	color: red;
}

注意點

  1. objectName是大小寫敏感的;
  2. "#"與ID之間不可以有空格;
  3. 由於objectName是所有QObject類對象的一個屬性,在運行過程中可以改變,所以一般情況下,要使用ID選擇器時,保證objectName不要在運行時被改變,否則重新加載stylesheet文件時,對應的ID選擇器將不會匹配到原來的控件。
  4. 由於objectName允許字符串中含有空格,但是ID選擇器彙總,ID是從緊跟#後的第一個字符開始直到遇到空格或"{"之間的字符串,因此,如果是爲了使用ID選擇器而設置objectName,則objectName中不能含有空格。
  5. 由於任何對象的objectName都可以出現重複,因此在設置objectName時,儘量保持其唯一性。
  6. Qt官方給出的ID選擇器的格式爲:
    className#ID {attribute: value; }
    
    但實際上不加類名也是可以的(加了類名的ID選擇器在CSS中被稱爲交集選擇器),在正式開發中,還是建議加上類名,因爲這樣可以看出這個ID選擇器所匹配的對象的類型,有利於提高閱讀性。
    基於以上特點,我們在設置objectName時,一般使用下劃線"_"連接的多個單詞表明此對象的功能。

一般用法:ID選擇器一般用於比較特殊的控件設置樣式,例如在應用程序的某個頁面中,需要突出一個重要的按鈕,那麼此時我們可以給這個按鈕設置一個獨特的樣式用以提醒用戶,如:

QPushButton#settings_popup_fileDialog_button
{
	min-height: 31px;
	min-width: 70px;
	border: 1px solid black;
	color: #FOFOFO;
	min-height: 10px;
	border-radius: 3px;
	background: qlineargradient(spread: pad, x1:0,y1:0,x2:0,y2:1,stop:0 #454648,stop:1 #7A7A7A);
}

五、後代選擇器

格式

selector1 selector2 { attribute: velue; }

這個選擇器表示:在選擇器1匹配的所有對象中,找到選擇器2匹配的所有後代對象,並給它們設置樣式。
注意點

  1. 後代選擇器必須使用空格隔開每個選擇器;
  2. 後代選擇器可以通過空格一直延續下去,例如:
    selector1 selector2 ... selectorN { attribute: velue; }
  3. 顧名思義,後代選擇器不僅包含“兒子”,還包含“孫子”,“重孫子”等,一般來說,只要B控件顯示在A控件上,那麼B控件就是A控件的後代。
  4. 後代選擇器不僅可以使用類型選擇器,還可以使用類選擇器,ID選擇器等。
  5. Qt中,各控件的父子關係:通過簡單的驗證,各控件的父子關係並非我們在創建對象時所指定的那樣,實際父子關係取決於如何佈局。
    一般用法:後代選擇器一般用於指定類的後代的樣式,例如在我的應用程序中,有很多相似的對話框,它們中包含一些樣式相同的按鈕,那麼我可以使用後代選擇器爲它們指定樣式,例如:
BaseDialog QPushButton
{
	min-width: 12px;
	min-height: 40px;
	max-width: 120px;
	max-height: 40px;
	font-size: 20px;
	padding: 0px;
}

六、子元素選擇器

格式

selector1>selector2 { attribute: value; }

子元素選擇器表示找到指定選擇器所匹配的對象中的所有特定直接子元素然後設置屬性,即找到選擇器1匹配到的對象中的被選擇器2匹配到的直接子元素然後設置屬性。
注意點

  1. 子元素選擇器必須用">“連接,”>"兩邊有沒有空格都可以,但是不建議寫空格,因爲會與後代選擇器的連接符混淆;
  2. 子元素選擇器只會查找“兒子”,不會查找其他後代;
  3. 子元素選擇器不僅可以使用類型選擇器,還可以使用類選擇器,ID選擇器;
  4. 子元素選擇器不能通過">“一直延續下去,只能有一個”>";
  5. 由於Qt中有繼承關係的Widgets較多,在使用子元素選擇器時,請特別注意繼承關係
    比如我只想選中QGroupBox中的QPushButton
    那麼我可以寫成:QWidget>QPushButoon{ color: red; } ①
    也可以寫成QGroupBox>QPushButton{ color: red; } ②
    這是因爲QGroupBoxQWidget的派生類,類型選擇器QWidget會選中所有它的派生類對象,這些對象中包括QGroupBox,因此寫法①會將所有的QPushButton的前景色設置爲紅色。
    鑑於此種情況,在使用子元素選擇器時,使用類選擇器替代類型選擇器。
    一般用法:子元素選擇器一般用於一些特定佈局條件中的控件,例如,我想給直接佈局在QGroupBox的QCheckBox設置一些特定屬性,那麼可以這麼做:
.QGroupBox>.QCheckBox
{
	color: blue;
}

七、屬性選擇器

格式

[attribute=value]{ attribute: value; }
[attribute|=value]{ attribute: value; }
[attribute~=value]{ attribute: value; }

attribute=value表示匹配有特定屬性attribute,並且值爲value的所有控件,然後設置樣式;
attribute|=value表示匹配有特定屬性attribute,並且值以value開頭的所有控件,然後設置樣式;
attribute~=value表示匹配有特定屬性attribute,並且值包含value的所有控件,然後設置樣式。
注意點
1、 attribute|=value表示attribute屬性的值以value開頭,無論value後面還有沒有值,或者value後面是什麼,均能匹配到,例如:

[objectName|="button"]
{
	color: red;
}

這表示將objectName屬性以button開頭的所有控件的前景色設置爲紅色。
2、 attribute~=value表示attribute屬性的值中包含value,這裏要注意的是value必須是獨立的單詞,也就是包含value並且value是被空格隔開的,例如:

[objectName~="button"]
{
	color: red;
}

在代碼中,設置的objectName的語句爲:

btn1->setObjectName("button123");
btn2->setObjectName("abc button 2");

結果只會匹配到btn2所指的對象
3、官方文檔的解釋:通常情況下,這裏的屬性指的是,使用Q_PROPERTY宏聲明的屬性,並且屬性類型要受QVariant::toString()支持。
這個選擇器類型也可以用來判斷動態屬性,要了解更多使用自定義動態屬性的細節,請參考使用自定義動態屬性。
處理使用=,還可以使用~=來判斷一個QStringList中是否包含給定的QString。
警告:如果在設置了樣式表後,相應的屬性值發生率改變(如flat變成了"true"),則有必要重新加載樣式表,一個有效的方法是,取消樣式表,再重新設置一次,下面的代碼是其中的一種方式:

style()->unpolish(this);
style()->polish(this);

一般用法:屬性選擇器一般不常用,如果要用,可以參照官方文檔的方法使用

八、並集選擇器

格式

selector1,selector2,selector3{ attribute: value; }

並集選擇器表示,將每個單獨選擇器匹配到的控件放在同一結果集中,並給結果集中的每個控件都設置聲明語句中的樣式。
注意點

  1. 並集選擇器必須使用","來連接不同的選擇器;
  2. 並集選擇器可以使用類選擇器,類型選擇器,ID選擇器,屬性選擇器等。

一般用法:主要用於給具有相同屬性並且外觀相似的控件設置樣式,例如:

.QLineEdit,.QComboBox
{
	border: 1px solid gray;
	background-color: white;
}

九、子控件選擇器

格式

類型選擇器::子控件{ 屬性:; }
類選擇器::子控件{ 屬性:; }

表示對類型選擇器或類選擇器指定的所有控件的子控件設置樣式;
Qt官方說明
爲了樣式化你的複雜widget,很有必要使用widget的subcontrol,比如QComboBox的drop-down部分或者是QSpinBox的上和下箭頭。選擇器也許會包含subcontrols用於限制widget的subcontrols,例如:

QComboBox::down-arrow
{
	image: url(:/res/arrowdown.png);
}

上述規則樣式話所有QComboBox的drop-down部分,雖然雙冒號(::)讓人聯想到CSS3的僞元素語法,但是Qt的Sub-Controls跟它是不一樣的。
Sub-Control始終相對於另一個元素來定義一個參考元素。這個參考元素可以是一個Widget又或者是另一個Sub-Control。例如,QComboBox的::drop-down默認被放置於QComboBox的Padding rectangle(盒子模型)的右上角。::drop-down默認會被放置於另一個::drop-down Sub-Control的中心。查看可樣式化的Widget列表以瞭解很多使用Sub-Control來樣式化Widget和初始化其位置的內容。
源rectangle可以使用subcontrol-origin來改變。舉個例子,如果我們想要把drop-down方式於QComboBox的margin rectangle而不是默認的Padding rectangle,我們可以像下面這樣指定:

QComboBox
{
	margin-right: 20px;
}
QComboBox::drop-down
{
	subcontrol-origin: margin;
}

drop-down在Margin rectangle內的排列方式可以由subcontrol-position來改變。
width和height屬性可以用來控制Sub-Control的size。需要注意的是,設置了image就隱式的設置了Sub-Control的size了。
相對定位方案(position:relative),允許Sub-Control的位置從它的初始化位置作出偏移。舉個例子,當QComboBox的drop-down按鈕被pressed時,我們也許想要那個箭頭作出位移以顯示一種"pressed"的效果,爲了達到目標,我們可以像下面那樣指定:

QComboBox::down-arrow
{
	image: url(down-arrow.png);
}
QComboBox::down-arrow:pressed
{
	position: relative;
	top: 1px; left: 1px;
}

絕對定位方案(position:absolute),使得Sub-Control的position和size基於其參考元素而改變。
一旦定位,它們將會與widget同等對待並且使用盒子模型來樣式化。
查看Sub-Control列表以瞭解哪些sub-control是被支持的,並且可以查看自定義QPushButton的菜單指示器Sub-Control來了解一個實際的使用例子。
注意:像QComboBox和QScrollBar這樣的複雜部件,如果sub-control的一項屬性是自定義的,那麼其他所有的屬性跟sub-control也都應該自定義。

十、僞類選擇器

格式

類型選擇器:狀態{ 屬性:; }
類選擇器:狀態{ 屬性:; }

表示對類型選擇器或類選擇器指定的所有控件設置它在指定狀態的樣式。
Qt官方說明
選擇器也許會包含基於widget的state的程序限制規則的僞狀態。僞狀態以冒號(:)作爲分隔緊跟着僞選擇器。舉個例子,下面的規則在鼠標懸浮在QPushButton的上方時生效:

QPushButton:hover { color: white }

僞狀態可以使用感嘆號進行取反,下面一條規則在鼠標沒有懸浮在QRadioButton上方時生效:

QRadioButton:!hover{ color: red }

僞狀態可以鏈接,在這樣的情況下,隱式地包含了邏輯與。舉個例子,下面的一條規則在鼠標懸浮到一個已check的QCheckBox上時生效:

QCheckBox:hover:checked { color: white }

僞轉態的取反也可以出現在僞狀態鏈彙總,舉個例子,下面的規則在鼠標懸浮到一個沒有被press的QPushButton上時生效:

QPushButton:hover:!pressed { color: blue }

如果有需要,可以使用逗號來表示邏輯或,即並集選擇器

QCheckBox:hover,QCheckBox:checked { color: white }

僞狀態可以與sub-control組合使用,舉個例子:

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

十一、沒有選擇器的情況

如果在C++的代碼中直接調用控件對象的setStyleSheet函數來設置樣式,但樣式中沒有任何選擇器,例如下面這樣:

btn1->setStyleSheet("color: green;");

即使這種寫法可以生效,但它不符合語法規則,因此不推薦使用。
經過測試,這樣的語句被忽略的選擇器相當於通用選擇器或下面例子中的選擇器,假如btn1是一個QPushButton對象的指針,那麼這條語句等價於:

btn1->setStyleSheet("QPushButton,QPushButton *{ color: green;}");

十二、選擇器的匹配規則

需要完成一個界面,如下圖所示:
在這裏插入圖片描述
這裏用戶名輸入框是一個QComboBox對象,密碼輸入框是一個QLineEdit對象,它們的父控件是一個QDialog,有這樣一個需求:給這兩個輸入框設置相同的邊框屬性:1個像素寬的藍色實線框,爲了方便更改風格,我有一個qss文件,將所有樣式都寫在這個文件裏,這時,觀察發現,這兩個控件都是QDialog的子控件,於是可以用後代選擇器或者子元素選擇器,如下:
第一種:

QDialog QComboBox,QLineEdit
{
	border:1px solid blue;
}

第二種:

QDialog>QComboBox,QLineEdit
{
	border:1px solid blue;
}

當寫完並運行程序後,發現無論採用哪種寫法QComboBox是正常的,但是我的程序界面中,其他所有的QLineEdit的邊框都變成了1個像素寬的藍色實線框,而這並不是我想要的效果。
因此對於上面的現象,我們很容易得出結論:多個選擇器組合使用時,它們的結合方向是自左向右,而不是我們認爲的自右向左。也就是說,這兩個選擇器分別被理解爲{ QDialog QComboBox },QLineEdit和{ QDialog>QComboBox },QLineEdit。
其實,這應該與CSS的選擇器匹配規則是一樣的,是爲了提高效率的一種做法,具體原因在此不細談。
正確的寫法應該是:

QDialog QComboBox,QDialog QLineEdit 
{
	border: 1px solid blue;
}

QDialog>QComboBox,QDialog>QLineEdit
{
	border: 1px solid blue;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章