學習Qss--Qss的特性

一、層疊性

qss的語法來源於css,而css的全稱是Cascading StyleSheet,翻譯過來叫做層疊樣式表,也叫級聯樣式表。層疊性是css處理衝突的一種能力,只有在多個選擇器匹配到同一個控件時纔會發生層疊性,例如:

btn1->setStyleSheet("QPushButton{ color: blue; }");
btn1->setStyleSheet(".QPushButton{ color: green; }");

這兩個選擇器匹配到了同一個按鈕,結果是後面的樣式覆蓋了前面的,這就是層疊現象。

二、繼承性(Qt-Version>=5.7)

在典型的CSS中,如果一個標籤的字體和顏色沒有顯示設置,它們會自動從其父親獲得。當使用Qt樣式表時,控件不會從其父親繼承字體和顏色的設置(請注意,父親和父類、孩子和子類都是不同的概念,不要搞混),例如,考慮一個QGroupBox內有一個QPushButton:

qApp->setStyleSheet("QGroupBox{ color: red; }");

QPushButton沒有任何顯示的color設置。因此,它會獲得系統的顏色而不是從父親繼承color的值。如果我們要設置QGroupBox及其所有孩子的color,我們可以這樣寫:

qApp->setStyleSheet("QGroupBox,QGroupBox *{ color: red; }");

注意QGrouBox和*之間的空格。
與此相反,使用QWidget::setFont()可以設置字體包括孩子的字體,使用QWidget::setPalette()可以設置調色板包括孩子的調色板。
如果想要字體和調色板被孩子繼承,可以給QApplication設置Qt::AA_UseStyleSheetPropagationInWidgetStyles(Qt5.7 加入)屬性,例如:

QCoreApplication::setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles,true);

三、優先級

當一個控件被多個選擇器選中並且設置了相同的屬性(值不同)時,不能僅僅根據設置樣式語句出現的先後順序進行層疊,那麼控件的樣式如果確定,於是引出了選擇器的優先級問題。一般通過下面兩步進行選擇器優先級的判定。
第一步:設置方式所產生的優先級問題
在CSS中,有如下層疊優先級規則:

內聯樣式 > 內部樣式 > 外部樣式 > 瀏覽器缺省

而在Qss中,這個規則表現爲:

給控件直接設置的樣式 > 給QApplication設置的樣式

就是說,調用控件的setStyleSheet設置的樣式的優先級永遠高於給QApplication設置的樣式,即使QApplication中的選擇器優先級更高。
第二步:樣式表本身的優先級問題
當設置方式相同,且幾個樣式規則爲同一個控件的同一個屬性指定不同的值時,就產生了衝突。此時,如何層疊就要由選擇器的優先級來確定。
一般而言,選擇器越特殊,它的優先級越高。也就是選擇器指向的越準確,它的優先級就越高。

優先級判斷的三種方式

  1. 間接選中
    間接選中就是指繼承,也就是在Qt5.7及以上版本,程序中給QApplication對象設置了Qt::AA_UseStyleSheetPropagationInWidgetStyles屬性時,纔會有間接選中。
    如果是間接選中,那麼最終的樣式就是離目標最近的那個,這裏的近指的是兩個控件的父子關係。例如一個QPushButton對象被佈局在QGroupBox中,而QGroupBox又被佈局在QWidget中,此時如果給QGroupBox和QWidget都設置了color屬性的顏色,那麼無論設置順序如何,QPushButton的前景色總是表現爲QGroupBox設置的顏色,因爲QGroupBox顯然是離QPushButton最近的那一個。
  2. 相同選擇器(直接選中)
    如果都是直接選中,並且都是同類型的選擇器,那麼寫在後面的樣式會覆蓋掉前面的樣式,例如:
    btn1->setStyleSheet("QPushButton{ color: green; }");
    btn1->setStyleSheet("QPushButton{ color: blue; }");
    
    顯而易見,btn1的前景色是藍色。
  3. 不同選擇器(直接選中)
    如果都是直接選中,並且不是相同類型的選擇器,那麼就會按照選擇器的優先級來層疊。
    具體的優先級如下:
    ID >> 類型 > 通配符 > 繼承 > 默認
    

優先級權重
當多個選擇器混合在一起使用時,我們可以通過計算權重來判斷誰的優先級最高,從而確定控件的樣式。

注意點:只有選擇器時直接選中控件是才需要計算權重,否則直接選擇器高於一切間接選中的選擇器。
優先級權重的計算方式:

  1. 計算選擇器中的id選擇器數量[=a]
  2. 計算選擇器中類選擇器的數量+屬性選擇器的數量[=b]
  3. 計算選擇器中類型選擇器的數量[=c]
  4. 忽略子控件選擇器

串聯這三個數字a-b-c就得到優先級權重,數字越大優先級越高。
Qt官方關於衝突解決的說明
當幾個樣式規則爲同一個屬性指定不同的值時,就產生了衝突。請考慮下面的樣式表:

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

兩條規則都匹配名爲okButton的QPushButton實例並且衝突於顏色屬性。爲了解決衝突,我們必須考慮到選擇器的特殊性。在上面的例子中,QPushButton#okButton被視爲比QPushButton更特殊,因爲它(通常)指向一個單一的對象,而不是QPushButton的所有實例。
相似的,指定了僞狀態的選擇器比沒有指定僞狀態的更特殊。從而,下面的樣式表指明瞭當鼠標懸浮到QPushButton上方時其字體顏色應該爲白色,而其餘情況爲紅色:

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

接下來看一個很有意思的:

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

兩個選擇器都有相同的特殊性,所以當鼠標懸浮在一個enabled的按鈕上時,第二條規則優先。如果在這種情況下我們想要文字變爲白色,我們可以像下面那樣重新排布一下樣式規則:

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

另外,我們可以使第一條規則更特殊一些:

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

相似的問題出現在相互配合的類型選擇器上。考慮以下情況:

QPushButton {  color: red; }
QAbstractButton { color: gary; }

兩條規則都應用於QPushButton的實例(因爲QPushButton繼承於QAbstractButton)並且衝突於color屬性。因爲QPushButton繼承於QAbstractButton,這讓人不禁想到QPushButton比QAbstractButton更特殊。然而,對於樣式表的運算,所有的類型選擇器都具有同等的特殊性,並且出現在更後面的規則優先級更高。換句話說,QAbstractButton的color會被設置成灰色,包括QPushButton。如果我們確實想要QPushButton字體顏色設置爲紅色,我們總是可以使用重新排列樣式表規則順序的方式實現。

爲確定規則的特殊性,Qt樣式表跟隨CSS2規範

一個選擇器的特殊性由下面的方式計算:

  • 計算選擇器中ID屬性的數量[=a]
  • 計算選擇器中其它屬性和僞類的數量[=b]
  • 計算選擇器中元素名字的數量[=c]
  • 忽略僞元素[如:subcontrol]

串聯這三個數字a-b-c(在一個大基數的數字系統)就得到了特殊性等級。例如:

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

四、盒模型

4.1、什麼是盒模型?

盒模型僅僅是一個形象的比喻,所有的widget都被看做是一個“盒子”,一個盒子包括:外邊距,邊框,內邊距,和實際內容。它們可以看做是有包含關係的矩形,並且這種包含關係是固定不變的。如圖所示:
在這裏插入圖片描述

  • Margin(外邊距):與其他盒子之間的距離;
  • Border(邊框):外邊距與內邊距之間的區域。邊框有自己的顏色不會受到盒子的背景顏色影響;
  • Padding(內邊距):內容和邊框之間的區域。會受到背景顏色的影響;
  • Content(內容):盒子的內容,顯示文本,圖像或其他控件。

除了內容外,其他三個部分均不能單獨設置顏色,智能設置其寬度,並且使以像素爲單位。

4.2、盒模型中的寬度與高度

在屬性中將要學到width,height兩個屬性,設置的均是盒子的內容的寬高,而我們在C++代碼中的窗口的width與height指的是整個盒子的寬度與高度,這一點非常重要。
整個盒子的寬度應該等於:

左外邊距+左邊框+左內邊距+內容寬度+右內邊距+右邊框+右外邊距

同理,整個盒子的高度也是上下外邊距,內邊距和內容高度的和。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章