Qt之QSS(樣式表語法)

轉自:https://blog.csdn.net/liang19890820/article/details/51691212

簡述

Qt樣式表(以下統稱QSS)的術語和語法規則幾乎和CSS相同。如果你熟悉CSS,可以快速瀏覽以下內容。

樣式規則

QSS包含了一個樣式規則序列,一個樣式規則由一個選擇器和聲明組成,選擇器指定哪些部件由規則影響,聲明指定哪些屬性應該在部件上進行設置。例如:

QPushButton { color: red }
  • 1

上面的例子中QPushButton是選擇器,{ color: red }是聲明,該規則指定QPushButton及其子類(例如:MyPushButton)應使用紅色作爲前景色。

QSS通常不區分大小寫(即:color、Color、COLOR、cOloR指同一屬性),唯一例外就是類名(class names)、對象名(object names)、屬性名(property names)區分大小寫。

幾個選擇器可以指定相同的聲明,使用逗號(,)來分隔選擇器。例如:

QPushButton, QLineEdit, QComboBox { color: red }
  • 1

相當於三個規則序列:

QPushButton { color: red }
QLineEdit { color: red }
QComboBox { color: red }
  • 1
  • 2
  • 3

聲明部分的規則是一個屬性值對(property: value)列表,包含在花括號中,以分號分隔。例如:

QPushButton { color: red; background-color: white }
  • 1

參考助手:Qt Style Sheets ReferenceList of Properties部分。

選擇器類型

目前爲止,所有的示例使用選擇器中最簡單的類型,類型選擇器。QSS支持所有的selectors defined in CSS2。下表總結了最有用的類型選擇器。

選擇器示例說明
通用選擇器*匹配所有部件
類型選擇器QPushButton匹配QPushButton及其子類的實例
屬性選擇器QPushButton[flat=”false”]匹配QPushButton中flat屬性爲false的實例。可以用此選擇器來測試任何支持QVariant::toString()的屬性,此外,支持特殊的類屬性、類名稱。此選擇器也可以用來測試動態屬性(參考助手:Qt Style Sheets ExamplesCustomizing Using Dynamic Properties部分)。還可以使用~=替換=,測試QStringList類型的屬性是否包含給定的QString。 警告:如果Qt屬性值在設置樣式之後更改,那麼可能需要強制重新計算樣式。實現的一個方法是取消樣式,然後重新設置一遍。
類選擇器.QPushButton匹配QPushButton的實例,但不包含子類。相當於*[class~=”QPushButton”]。
ID選擇器QPushButton#okButton匹配所有objectName爲okButton的QPushButton實例。
後代選擇器QDialog QPushButton匹配屬於QDialog後代(孩子,孫子等)的QPushButton所有實例。
子選擇器QDialog > QPushButton匹配屬於QDialog直接子類的QPushButton所有實例。

子控件

對於樣式複雜的部件,需要訪問子控件,例如:QComboBox的下拉按鈕或QSpinBox的上下箭頭。選擇器可能包含子控件,使得可以限制特有部件子控件的應用規則。例如:

QComboBox::drop-down { image: url(dropdown.png) }
  • 1

上述規則指定了QComboBoxe下拉按鈕樣式,雖然雙冒號(::)語法讓人想起CSS3僞元素,但Qt子控件從概念上講有不同的級聯語義。

子控件定位總是相對於另一個參考元素。這個參考元素可能是小部件或其它子控件。例如:QComboBox的::drop-down放置,默認的放置在QComboBox區域的右上角,::drop-down放置,默認的在::drop-down子控件的中央,參考助手:Qt Style Sheets ReferenceList of Stylable Widgets部分。

可以使用subcontrol-origin改變子控件原始的默認位置,

QComboBox {
    margin-right: 20px;
}
QComboBox::drop-down {
    subcontrol-origin: margin;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

下拉的對齊方式可以通過subcontrol-position屬性改變。

width和height屬性可用於控制子控件的大小,注意:設置一個圖片會隱式地設置子控件的大小。

相對定位(position : relative):可以改變子控件相對初始位置的偏移量。例如:按下QComboBox下拉按鈕時,我們可能更喜歡用內部箭頭偏移量來產生一個被按下的效果。要做到這一點,我們可以指定:

QComboBox::down-arrow {
    image: url(down_arrow.png);
}
QComboBox::down-arrow:pressed {
    position: relative;
    top: 1px; left: 1px;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

絕對定位(position : absolute):允許子控件改變位置和的大小而不受參考元素限制。一旦位置被設定,這些子控件將被和普通部件(widgets)視爲相同,並且可以使用盒模型樣式(參考助手:Customizing Qt Widgets Using Style SheetsThe Box Model部分)。

參考助手:Qt Style Sheets ReferenceList of Sub-Controls部分,及Qt Style Sheets ExamplesCustomizing the QPushButton's Menu Indicator Sub-Control部分。

注意:對於複雜的部件,如:QComboBox和QScrollBar,如果一個屬性或子控件被定製,所有其它屬性或子控件必須被定製好。

僞選擇器

選擇器可以包含僞狀態,意味着限制基於部件狀態的應用程序規則。僞狀態出現在選擇器後面,用冒號(:)關聯。例如,鼠標劃過按鈕:

QPushButton:hover { color: white }
  • 1

僞狀態可以用感嘆號(!)運算符表示否定。例如,當鼠標不劃過QRadioButton:

QRadioButton:!hover { color: red }
  • 1

僞狀態可以連接使用,這種情況下,相當於隱含了一個邏輯與。例如,當鼠標滑過選中的QCheckBox:

QCheckBox:hover:checked { color: white }
  • 1

否定的僞狀態也可以連接使用,例如,當鼠標劃過一個非按下時按鈕:

QPushButton:hover:!pressed { color: blue; }
  • 1

如果需要,也可以使用逗號操作來表示邏輯或:

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

僞狀態也可以與子控件組合,例如:

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

參見助手:Qt Style Sheets ReferenceList of Pseudo-States部分。

解決衝突

當樣式中指定相同的屬性具有不同的值時,就會出現衝突。例如:

QPushButton#okButton { color: gray }
QPushButton { color: red }
  • 1
  • 2

兩個規則匹配objectName爲okButton的QPushButton實例,color屬性有衝突。要解決這個衝突,必須考慮到的選擇器的特殊性。上面的例子,QPushButton#okButton被認爲比QPushButton更具體,因爲它通常是指單個對象,而不是一類的所有實例。

同樣的,利用僞狀態比不指定僞狀態那些選擇器更具體。因此,下面的樣式指定一個QPushButton應該有鼠標懸停文本白色,否則文本紅色效果:

QPushButton:hover { color: white }
QPushButton { color: red }
  • 1
  • 2

這裏有一個複雜的:

QPushButton:hover { color: white }
QPushButton:enabled { color: red }
  • 1
  • 2

這裏,兩個選擇器有相同的特殊性,如果鼠標在按鈕上時,第二條規則優先。如果在這種情況下我們想要白色文本,需要重新排序規則:

QPushButton:enabled { color: red }
QPushButton:hover { color: white }
  • 1
  • 2

或者,可以使第一條規則更加具體:

QPushButton:hover:enabled { color: white }
QPushButton:enabled { color: red }
  • 1
  • 2

類似的問題出現在類型選擇器一起使用。請看下面的例子:

QPushButton { color: red }
QAbstractButton { color: gray }
  • 1
  • 2

兩個規則應用於QPushButton實例(因爲QPushButton繼承自QAbstractButton)並有color屬性的衝突。因爲QPushButton繼承QAbstractButton,所以QPushButton比QAbstractButton更具體。

然而,對於QSS的計算,所有的類型選擇具有相同的特殊性,最後出現的規則優先。換句話說,所有的QAbstractButton顏色設置爲灰色(包括QPushButton)。如果需要設置QPushButtons爲紅色文字,我們總能重新排序規則。

爲了確定一個規則的特殊性,QSS遵循CSS2規範

一個選擇器的特殊性的計算方法如下:

  • 計算選擇器中ID屬性的數量(= a)
  • 計算選擇器中僞狀態類和其它屬性的數量(= b)
  • 計算選擇器中元素名的數量(= c)
  • 忽略僞元素(即子控件)。

串聯的三個數字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 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

級聯效應

QSS可以在QApplication、父部件、子部件中設置。任意部件的有效樣式表通過合併部件的祖先(父親,祖父等)以及任何QApplication上設置的樣式表。

衝突發生時,不論衝突規則的特殊性,部件自身的樣式表總優先於任何繼承樣式表。同樣,父窗口部件樣式表優先於祖父等。

這樣,一個部件設置樣式自動使得它比在祖先部件或QApplication的樣式表中指定的其它規則的優先級高。考慮下面的例子。首先,我們在QApplication中設置樣式表:

qApp->setStyleSheet("QPushButton { color: white }");
  • 1

然後,我們設置QPushButton的樣式表:

myPushButton->setStyleSheet("* { color: blue }");
  • 1

QPushButton樣式表強制QPushButton(以及任何子部件)顯示藍色文字,儘管應用程序範圍內的樣式表提供的規則更具體。

如果按照下面這種方式寫,其結果是相同的:

myPushButton->setStyleSheet("color: blue");
  • 1

但如果QPushButton有孩子(不太可能),樣式表就不會對它們有效果。

樣式表級聯是一個複雜的話題。請參考CSS2 Specification,要知道目前Qt沒有實現。

繼承性

在經典的CSS中,當字體和顏色沒有明確設置時,它就會自動從父繼承。當使用QSS時,部件不會自動從父繼承字體和顏色。

例如,一個QGroupBox中包含QPushButton:

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

QPushButton沒有一個明確的顏色設置,因此,不是繼承其父QGroupBox的顏色,而是顯示系統的顏色。如果要建立一個QGroupBox及其孩子的顏色,可以這樣寫:

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

相比之下,可以用QWidget::setFont() 和 QWidget::setPalette()爲子部件設置字體和畫板 。

Namespaces中的部件

類型選擇器可用於某一特定類型的部件。例如:

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

// ...
qApp->setStyleSheet("MyPushButton { background: yellow; }");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

QSS使用部件的QObject::className()來確定何時應用類型選擇器。當自定義的部件在命名空間中時,QObject::className()返回<namespace>::<classname>。這與子控件的語法衝突。爲了解決這個問題,當命名空間內的部件使用類型選擇器時,必須更換”::” 爲 “–”。 例如:

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

// ...
qApp->setStyleSheet("ns--MyPushButton { background: yellow; }");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

設置對象屬性

從4.3及以後,任何可被識別的Q_PROPERTY都可以使用qproperty-<property name>語法設置。

例如:

MyLabel { qproperty-pixmap: url(pixmap.png); }
MyGroupBox { qproperty-titleColor: rgb(100, 200, 100); }
QPushButton { qproperty-iconSize: 20px 20px; }
  • 1
  • 2
  • 3

如果屬性引用Q_ENUMS聲明的枚舉,則應該參考其常量的名字,而不是數值。

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