QT StyleSheet(二)

來源:互聯網
上載者:User
2011-09-15 13:49

http://www.developer.nokia.com/Community/Wiki/%E4%BD%BF%E7%94%A8Qt_Style_Sheets%E5%88%B6%E4%BD%9CUI%E7%89%B9%E6%95%88

除了子類化Style類,使用QT樣式表(QStyleSheet)是另一種快速改變QT程式UI風格的方法,它很大程度上借鑒和參考了 HTML層疊樣式表的文法和思想。其效果疊加在Style的基礎上

按官方文檔的說法,QT樣式表目前只能和內建Style配合工作,和子類化的Style的配合正在開發中

StyleSheet的使用
StyleSheet檔案的預設尾碼名為qss,可以通過命令列參數 -stylesheet filename.qss 來設定樣式表,也可以通過QApplication::setStyleSheet 或 QWidget::setStyleSheet來設定應用程式或特定控制項要使用的樣式表

::setStyleSheet函數的參數是字串(不是qss檔案的名字,而是樣式表的內容),所以直接使用的話,不方便一次設定大量的規則,但 是可以使用資源檔將qss樣式表嵌入到程式中,然後通過QApplication::setStyleSheet來使用,例如:

QFile file(":/qss/mystylesheet.qss");
file.open(QFile::ReadOnly);
app.setStyleSheet(file.readAll());

樣式表文法
這裡不打算詳細解釋,只是舉例說明,具體的文法規則,請參考 http://qt.nokia.com/doc/4.6/stylesheet-syntax.html

一條樣式表的描述規則可能類似這樣:

QComboBox#myComboBox::down-arrow:pressed {
position: relative;
top: 1px; left: 1px;
}

一條樣式表規則由選取器 (Selector)和屬性定義(declaration)組成。

QComboBox#myComboBox::down-arrow:pressed

這部分是選取器,用於指定樣式表規則的應用對象,細分開來:

QComboBox#myComboBox 這一部分叫類型選取器(Type Selector),QComboBox指定了對象類名,#name指定對象的執行個體名(非必須)其它的選取器文法請參考官方文檔。 
down-arrow 子控制項描述符(subcontrol),和前面的欄位用::隔開,這裡表示組合框的下拉按鍵 
pressed 偽狀態(Pseudo-States)描述符,和前面的欄位用:隔開,這裡表示壓下狀態 
以上除了第一個欄位,都不是必須,而是進一步限制規則適 用範圍

view plaincopy to clipboardprint?
{   
position: relative;   
top: 1px; left: 1px;   
}  
{
position: relative;
top: 1px; left: 1px;
}

這部分是屬性定義,由成對的屬性名稱:屬性值組成,用;分隔。

QSS文法

同css一樣,他也有由一個selector與一個declaration組成,selector指定了是對哪一個控制項產生效果,而 declaration才是真正的產生作用的語句。如: 
QPushButton { color: red }

QPushButton指定了是對所有的QPushButton或是其子類控制項(如使用者定義的MyPushButton)產生影響,而 color:red表明所有的受影響控制項的前景色彩都為red。

除了"類名","對象名","Qt屬性名稱"這三樣東西是大小寫敏感的外其他的東西都是大小寫不敏感的,如color與Color代表同 一屬性。

如果有幾個selector指定了相同的declaration, 可以使用逗號(,)將各個選取器分開,如: 
QPushButton, QLineEdit, QComboBox { color: red }

他相當於: 
QPushButton { color: red } 
QLineEdit { color: red } 
QComboBox { color: red }

declaration部份是一系列的(屬性:值)對,使用分號(;)將各個不同的屬性值對分開,使用大括弧({})將所有declaration 包含在一起。

 一般選取器(selector)

Qt支援所有的CSS2定義的選取器,其祥細內容可以在w3c的網站上尋找http://www.w3.org/TR/CSS2/selector.html ,
其中比較常用的selector類型有:

i. 通用類型選取器:*

會對所有控制項有效果。

ii. 類型選取器:QPushButton

匹配所有QPushButton的執行個體和其子類的執行個體。

iii. 屬性選取器:QPushButton[flat="false"]

匹配所有QPushButton屬性flat為false的執行個體,屬性分為兩種,靜態和動態,靜態屬性可以通過Q_PROPERTY() 來指定,來動態屬性可以使用setProperty來指定,如: 
QLineEdit *nameEdit = new QLineEdit(this); 
nameEdit->setProperty("mandatoryField", true);

如果在設定了qss後Qt屬性改變了,需要重新設定qss來使其生效,可以使用先unset再set qss。

iv. 類別選取器:.QPushButton

匹配所有QPushButton的執行個體,但不包含其子類,這相當於:

*[class~="QPushButton"]

~=的意思是測試一個QStringList類型的屬性是否包含給定的QString。

v. ID選取器:QPushButton#okButton

對應Qt裡面的object name設定,使用這條CSS之前要先設定對應控制項的object name為okButton,如:

Ok->setObjectName(tr("okButton"));

vi. 後裔選取器:QDialog QPushButton

匹配所有為QDialog後裔(包含兒子,與兒子的兒子的遞迴)為QPushButton的執行個體

vii. 子選取器:QDialog > QPushButton

匹配所有的QDialog直接子類QPushButton的執行個體,不包含兒子的兒子的遞迴。

2, 子控制項選取器

i. 對於複雜的控制項,可能會在其中包含其他子控制項,如一個QComboxBox中有一個drop-down的按鈕。那麼現在如果要設定QComboxBox的 下拉按鈕的話,就可以這樣訪問: 
QComboBox::drop-down { image: url(dropdown.png) }

其標誌是(::)

ii. 子控制項選取器是用位置的引用來代表一個元素,這個元素可以是一個單一控制項或是另一個包含子控制項的複合控制項。使用subcontrol-origin屬性可 以改變子控制項的預設置放位置,如: 
QComboBox { 
margin-right: 20px; 
} 
QComboBox::drop-down { 
subcontrol-origin: margin; 
}

如上語句可以用來改變drop-down的margin。

iii. 相對位置屬性可以用來改變子控制項相對於最初位置的位移量,如當一個QCombox的drop-down按鈕被按下時,我們可以用一個內部的小位移量來表示 被按下的效果,如下: 
QComboBox::down-arrow { 
image: url(down_arrow.png); 
} 
QComboBox::down-arrow:pressed { 
position: relative; 
top: 1px; left: 1px; 
}

iv. 絕對位置屬性允許子控制項改變自己的位置和大小而不受引用元素的控制項。一但位置被設定了,這些子控制項就可以被當成一般的widget來對待,並且可以使用合 模型。關於合模型可以參考下面。

如果你要查看Qt支援哪些子控制項選取器,可以參考:

http://pepper.troll.no/s60prereleases/doc/stylesheet-reference.html#list-of-sub-controls

-syntax.html

3, 偽選取器(pseudo-states)

i. 偽選取器以冒號(:)表示,與css裡的偽選取器相似,是基於控制項的一些基本狀態來限定程式的規則,如hover規則表示滑鼠經過控制項時的狀態,而 press表示按下按鈕時的狀態。如:

QPushButton:hover {

Background-color:red;

}

表示滑鼠經過時QPushButton背景變紅。

ii. Pseudo還支援否定符號(!),如: 
QRadioButton:!hover { color: red }

表示沒有滑鼠移上QRadioButton時他顯示的顏色是red。

iii. Pseudo可以被串聯在一起,比如: 
QPushButton:hover:!pressed { color: blue; }

表示QPushButton在滑鼠移上卻沒有點擊時顯示blue字,但如果點擊的時候就不會顯示blue顏色了。

iv. 同樣可以和之前所講的子控制項選取器一起聯合使用,如:

QSpinBox::down-button:hover { image: url(btn-combobox-press.bmp) }

v. 與前面所講的一樣,偽選取器,子控制項選取器等都是可以用逗號(,)分隔表示連續相同的設定的,如:

QPushButton:hover,QSpinBox::down-button, QCheckBox:checked { color: white ;image: url(btn-combobox-press.bmp);} 表示如下

vi. 更多請參考:

http://pepper.troll.no/s60prereleases/doc/stylesheet-reference.html#list-of-pseudo-states

使用Qt Style Sheet(2) 
2009-10-30 16:51

2, 解決衝突

a) 使用object name

i. 在程式裡面要先設定控制項的,如:

btnOne = new QPushButton(centralWidget);

btnOne->setObjectName(QString::fromUtf8("btnOneCh"));

ii. 這樣,我們有了一個object name為btnOneCh的QPushButton,實驗一下,使用指定object name的方式,如:

QPushButton#btnOneCh { color: red }

QPushButton { color: white }

可以看出,btnOncCh的color變成了red

b) 使用偽選取器,如hover,press,enabled等,如:

i. 按扭"1"是disable了的,

QPushButton:!enabled {color: white}

c) 所有的類型選取器都有一個共同的特性,就是如果有兩個屬性衝突了的話就會以最後出現的一個為準,如:

QPushButton { color: red }

QAbstractButton { color: gray }

由於QPushButton為QAbstractButton的子類,如果只設定QAbstractButton的可以想像結果是所有的 QPushButton都為gray, 如果只設定QPushButton的所有QPushButton都會為red,當兩個都能設定起效的時候,以在文本上最後出現的為準,所以結果為Grey

d) 當然其中如果有#指定了object name,他所設定的優先順序是最大的,具體規則可以參考:http://www.w3.org/TR/CSS2/cascade.html#specificity , 或是

http://pepper.troll.no/s60prereleases/doc/stylesheet-syntax.html#conflict-resolution

QPushButton#btnOneCh { color: red }

QPushButton { color: blue }

QAbstractButton { color: gray }

雖然QAbstractButton在最後,但是之前有#btnOneCh指定了QPushButton"一"的color為red所以最 後顯示也是"一"為red。

3, 級聯效應

a) 子類可以繼承父類的StyleSheet,但是如果子類裡面設定了StyleSheet與父類裡在設定的有衝突,那麼當然會優先考慮子類自己的,同樣,如 果在qApp時面設定了,但是在某一個特定控制項裡面也設定,如果有衝突,也是優先控制項自己的,例如,我在程式時面設定了:

btnOneEn->setStyleSheet("QPushButton { color: red }");

而,當我再設定qApp時,如果,將QPushButton的color設定成grey的,那麼結果是對於btnOneEn這個 QPushButton來說他的顏色還是red。

這就是為什麼這裡設定為grey了btnOneEn卻還是red的。

b) 如果我們對一個控制項設定StyleSheet為: 
QPushButton* myPushButton; 
myPushButton->setStyleSheet("* { color: blue }");

其實他和設定為: 
myPushButton->setStyleSheet("color: blue"); 
效果相同, 只是後一種設定不會對QPushButton的子類產生作用,但第一種卻會。

4, 繼承性

a) 與CSS不同的一點,在CSS box模型中,如果一個元素在別一元素的裡面,那麼裡面的元素會自動繼承外面元素的屬性,但QSS裡面不會,如:

一個QPushButton如果放在一個QGroupBox裡面,如果: 
qApp->setStyleSheet("QGroupBox { color: red; } ");

並不代表在QGroupBox裡面的QPushButton也會有color:red的屬性,如果要想有的話要顯示寫明,如: 
qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");

或者在應用程式裡面也可以用QWidget::setFont等來設定到子控制項的屬性。

5, Namespace衝突

a) 類型選取器能夠使用到一個特定的類型,如: 
class MyPushButton : public QPushButton { 
// ... 
} 
qApp->setStyleSheet("MyPushButton { background: yellow; }");

因為QSS使用QObject::className來判斷要賦與style sheet的控制項類型,如果一個使用者定義控制項類型在一個namespace裡面的話,QObject::className會返 回<namespace>::<classname> 的名字,這和子控制項選取器的文法相衝突,為瞭解決此問題,使用"--"來代替"::",比如: 
namespace ns { 
class MyPushButton : public QPushButton { 
// ... 
} 
} 
qApp->setSytleSheet("ns--MyPushButton { background: yellow; }");

6, 設定對像屬性

a) 如果在程式裡面使用Q_PROPERTY設定的屬性,可以在qss裡面使用:qproperty-<property name>的形式來訪問並設定值。如: 
MyLabel { qproperty-pixmap: url(pixmap.png); } 
MyGroupBox { qproperty-titleColor: rgb(100, 200, 100); } 
QPushButton { qproperty-iconSize: 20px 20px; }

如果屬性引用到的是一個由Q_ENUMS申明的enum 時,要引用其屬性名稱字要用定義的名稱而不是數字。

 

 

樣式表規則的範圍和優先順序關係
因為樣式表規則的層級關係比較複雜,另外設定的方式也有很多,有時候會發生多條規則都和某一個具體控制項相關的 情況,這樣具體哪一條樣式表規則最終被應用到控制項的UI表現上,就需要有一個規則來定義,大致上牽涉到這個問題的情況有如下幾種

規則衝突

多條規則制定了不同的內容,可能的情況有很多,比如

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

這種情況,其實可以不算衝突,更加具體的類型描述元定義的規則擁有更高優先順序,所以一個有滑鼠移至上方的按鈕的文本顏色就是白色的,否則為紅色

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

這裡就可能發生規則衝突,當一個使能的按鈕有滑鼠移至上方的時候,顏色的定義是什麼呢? QStyleSheet的判斷原則是,後面規則的優先順序高於前面的規則,所以這種情況顏色為紅色

QPushButton { color: red }
QAbstractButton { color: gray }

這個相對難發現,一個基類及其子類都定義了針對文本顏色的規則,那麼子類應用哪一條規則呢?你可能會認為自然是子類用自己的規則了,很可惜不是,樣 式表不考慮類的繼承層級優先關係,所以還是後一條規則優先順序高於前一條規則。如果確實要單獨設定子類的規則,需要交換規則的順序。

樣式表層疊 Cascading

因為樣式表可以應用在QApplication上,也可以單獨應用在控制項上,所以最終應用到一個具體控制項的樣式表,是通過疊加合并所有的父控制項乃至 應用程式的樣式表設定來得到的。這種情況下,也有可能發生規則衝突, 例如:

view plaincopy to clipboardprint?
qApp->setStyleSheet("QPushButton { color: white }");   
myPushButton->setStyleSheet("* { color: blue }");  
qApp->setStyleSheet("QPushButton { color: white }");
myPushButton->setStyleSheet("* { color: blue }");

這種情況下,控制項自身的樣式表的優先順序高於父控制項或應用程式的樣式表

樣式表繼承 Inheritance

在標準的CSS樣式表中,一個控制項的字型和顏色屬性如果沒有明確設定,那麼將自動繼承自父控制項,而在QT的樣式表中,不會自動繼承,例如:

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

這種情況下,對於GroupBox中的添加的子控制項,不會自動化佈建其顏色屬性,如果要設定子控制項的屬性,需要明確設定:

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

注意,這裡的繼承和上面的層疊不一樣,層疊指不同樣式表設定同一個對象,繼承指的則是樣式表規則中選取器對控制項層級關係的影響

Stylesheet是如何附加在Style上的
當設定StyleSheet的時候,一個QStyleSheetStyle會被產生並被設 為應用程式實際的Style,而當前的Style則被reparent成QStyleSheetStyle的子物件,當應用程式或控制項調用Style繪圖 的時候,實際調用的是QStyleSheetStyle對象,在QStyleSheetStyle類內部,會先調用函數按照StyleSheet定義的規 則繪製UI,如果沒有相關規則,再調用當前的Style對象的繪圖函數繪製UI,所以QStyleSheet作為一個代理Style先對UI進行處理。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.