使用Qt Style Sheets制作UI特效
引言
作為一套GUI框架,Qt是非常強大的。(注:Qt 不僅是一套優(yōu)秀的GUI框架,同時也是一套出色的應(yīng)用程序框架)。
在UI的制作方面Qt為廣大開發(fā)者提供了一套強大而易用的工具,她就是——Qt Style Sheets。
本文將向大家舉例介紹如何使用Qt Style Sheets制作個性化的UI界面。例子程序(stylesheetDemo)可通過本文末尾所附鏈接下載。
UI涉及的東西非常龐雜,Qt Style Sheets也包含許許多多的內(nèi)容,因此本文并不試圖對Qt Style Sheets進行系統(tǒng)的理論性的詳解,那需要數(shù)十倍于本文的篇幅。本文僅通過幾個例子,將大家引入Qt Style Sheets的大門,以后如有更多需求大家直接在Qt Assistant中查詢Qt Style Sheets并且結(jié)合自己寫的程序進行測試就可以了。
測試設(shè)備
Nokia N8
預(yù)備知識
Style sheets 是由一系列的style rules組成的。一條style rule 由選擇器selector和聲明declaration這兩部分構(gòu)成。selector說明這條規(guī)則在哪些widgets上起作用,declaration說明要在這些widgets上設(shè)置什么屬性properties。例如:
QPushButton,?QLineEdit??{?color:?red;?background-color:?white?}
在上面這條style rule中QPushButton, QLineEdit 是兩個選擇器,中間用逗號連接。 { color: red; background-color: white }是聲明declaration,大括號里面是一系列的 property: value對,中間用分號連接。這條規(guī)則指出對QPushButton和QLineEdit 以及他們的子類需要使用紅色作為其前景色,并使用白色作為其背景色。
Qt widgets所支持的所有屬性列表請查閱List of Properties
Tab1:QLineEdit QGroupBox QRadioButton QCheckBox QLabel(使用qss文件)
例子程序的UI結(jié)構(gòu)非常簡單,只有兩部分,上方是一個有三個tab頁面的QTabWidget,下面是一個QPushButton。
下面我們先來制作TabWidget的第一個頁面Tab1。先看一下效果圖:
圖一:
圖二:
這張是沒有使用StyleSheet的樣子:
Tab1中使用到了五種控件。如果控件較多或比較復(fù)雜,我們可以通過使用qss文件來設(shè)置Style Sheet。首先我們新建一個文本文檔,后綴名改為qss,然后用文本編輯器比如記事本打開它,將我們設(shè)置的Style Sheets寫進去然后保存就可以了。本例程創(chuàng)建的qss文件叫stylesheetDemo.qss,于是我們在程序中只需要寫如下幾行代碼就可以使我們寫在qss文件中的Style Sheets起作用:
QFile?file(":/qss/stylesheetDemo.qss"); file.open(QFile::ReadOnly); QTextStream?filetext(&file); QString?stylesheet?=?filetext.readAll(); ui->tab->setStyleSheet(stylesheet);
程序中stylesheetDemo.qss已加入到資源文件,其中ui->tab就是TabWidget中的第一個tab頁面。
下面是stylesheetDemo.qss的內(nèi)容:
QGroupBox?{ background-image:?url(:/pics/background.png);? border-radius:?30px; } ? QLabel?{ color:?gray; } ? QLineEdit?{ background:?qradialgradient(cx:0,?cy:0,?radius:?1, ????????????fx:0.5,?fy:0.5,?stop:0?white,?stop:1?rgba(0,190,0,?60%)); border-radius:?9px; } ? ? ? QCheckBox:checked?{ color:?green;????? } ? QCheckBox::indicator?{ ??????width:?25px; ??????height:?25px; } ? QCheckBox::indicator:checked?{ ????? image:?url(:/pics/checkbox.gif); } ? ? ? QRadioButton{ ??????spacing:?10 } ? QRadioButton::indicator?{ ??????width:?25px; ??????height:?25px; } ? QRadioButton:checked?{ ??????color:?rgb(230,115,?0);????? } ? QRadioButton::indicator:checked?{ ??????image:?url(:/pics/radioButton.png); }
其中border-radius指的是邊框四角的半徑,這一屬性可以制作出弧形的邊框。
background-image屬性設(shè)置控件的背景圖片。
background-color 設(shè)置控件的背景色,我們這里對QLineEdit使用了漸變的顏色,這里利用了Qt提供的qradialgradient
一個冒號說明的是狀態(tài),例如“:checked”指的是當(dāng)此控件被checked的時候。
雙冒號說明的是子控件,例如“::indicator”指的是 QCheckBox、QRadioButton、QAbstractItemView 或者是可以被選中的 QMenu item或QGroupBox的indicator。
這里需要注意的是,由于QRadioButton和QCheckBox在Symbian上的實現(xiàn)有一點缺憾,就是他們在獲得焦點的時候,其新的背景顏色會完全覆蓋掉控件,用戶就看不到控件了。因此我們需要去掉他們獲得焦點的能力:
ui->checkBox->setFocusPolicy(Qt::NoFocus); ui->checkBox_2->setFocusPolicy(Qt::NoFocus); ui->radioButton->setFocusPolicy(Qt::NoFocus); ui->radioButton_2->setFocusPolicy(Qt::NoFocus);
Tab2:QTextBrowser (在代碼中setStyleSheet)
程序中對TextBrowser設(shè)置了一種透明的背景顏色,并且是像彩虹一樣逐漸變化的顏色。這主要是利用了qlineargradient。下面分別是豎屏和橫屏狀態(tài)下Tab2的效果圖:
圖三:
圖四:
這張是沒有使用StyleSheet的樣子:
我們這里直接在代碼中對textBrowser設(shè)置StyleSheet:
ui->textBrowser->setStyleSheet(" ????????????color:?rgb(127,?0,?63); ????????????background-color:?qlineargradient(x1:?0,?y1:?0,?x2:?1,?y2:?1,? ????????????????????????????????stop:?0?rgba(255,?0,?0,?30%),?stop:?0.2?rgba(255,?128,?0,?30%),?stop:?0.4?rgba(255,?255,?0,?30%),? ????????????????????????????????stop:?0.6?rgba(0,?255,?0,?30%),?stop:?0.8?rgba(0,?128,?255,?30%),?stop:?1?rgba(128,?0,?255,?30%));? ????????????selection-color:?white; ????????????selection-background-color:?rgb(191,?31,?127); ????????????border:?2px?groove?gray; ????????????border-radius:?30px; ????????????padding:?2px?4px;");
Tab3:QWebView
QWebView也是可以通過Qt Style Sheets的方式在一定程度上修改網(wǎng)頁呈現(xiàn)在用戶面前的樣子。
例程中對WebView設(shè)置了完全透明的背景色,下面是效果圖:
圖五:
圖六:
圖七:
這張是沒有使用StyleSheet的樣子:
ui->webView->setStyleSheet("border:?1px?groove?gray;?border-radius:?5px;?background-color:?rgba(255,?193,?245,?0%);?");
這里要注意,這樣設(shè)置只對本身透明的網(wǎng)頁是有效的,如果網(wǎng)頁自己設(shè)置了白色背景,則我們還是看不到透明的效果。
還要額外說明一點,如果不對webView的border屬性進行設(shè)置,而使用QWebView在N8上的默認(rèn)實現(xiàn),則網(wǎng)頁中的Button是黑色的背景,Button上的字是看不清的。
要想完全使網(wǎng)頁按照我們自定義的樣式進行顯示(渲染),最根本的解決辦法是我們修改Webkit,從而渲染出我們需要的樣子。
QPushButton QTabWidget
對比圖一和圖二,我們會發(fā)現(xiàn)exit按鈕按下和沒有按下時的背景、文字顏色和文字位置都是不一樣的,其中背景是通過border-image實現(xiàn)的,文字的位置是通過padding來控制的。
ui->ExitpushButton->setStyleSheet(" ??????????????????????????????????????QPushButton?{ ????????????????????????????????????????????color:?white; ????????????????????????????????????????????border-image:?url(:/pics/button.png); ????????????????????????????????????????????border-width:?12px; ????????????????????????????????????????????padding:?-12px?0px; ????????????????????????????????????????????min-height:?25px; ????????????????????????????????????????????min-width:?60px; ????????????????????????????????????????????} ??????????????????????????????????????QPushButton:pressed?{ ????????????????????????????????????????????color:?lightgray; ????????????????????????????????????????????border-image:?url(:/pics/button-pressed.png);? ????????????????????????????????????????????padding-top:?-10px; ????????????????????????????????????????????padding-bottom:?-16px; ????????????????????????????????????????????} ??????????????????????????????????????");
對于三個tab標(biāo)簽的樣式是這樣設(shè)置的,其中!selected表示沒有選中,margin-top: 5px;會使得選中的tab比沒選中的高5個像素。
ui->tabWidget->setStyleSheet(" ?????????????????????????????????QTabBar::tab?{ ????????????????????????????????????????color:?rgb(84,2,119); ????????????????????????????????????????background-image:?url(:/pics/wood.jpg);? ????????????????????????????????????????border:?2px?solid?rgb(68,66,64); ????????????????????????????????????????border-bottom-color:?rgb(68,66,64);? ????????????????????????????????????????border-top-left-radius:?20px; ????????????????????????????????????????border-top-right-radius:?20px; ????????????????????????????????????????max-height:?21px; ????????????????????????????????????????min-width:?8ex; ????????????????????????????????????????padding:?2px; ????????????????????????????????????????}? ??????????????????????????????????QTabWidget::tab-bar?{ ????????????????????????????????????????alignment:?center; ????????????????????????????????????????}? ??????????????????????????????????QTabBar::tab:!selected?{ ????????????????????????????????????????margin-top:?5px;? ????????????????????????????????????????} ??????????????????????????????????QTabBar::tab:selected?{ ????????????????????????????????????????color:?rgb(255,0,128);? ????????????????????????????????????????} ??????????????????????????????????");
最后橫豎屏背景圖片的切換也是通過stylesheet實現(xiàn)的:
void?MainWindow::resizeEvent?(?QResizeEvent?*?event?) { ????enum?ScreenMode?currentscreenMode; ????if(size().height()>?size().width()) ????????currentscreenMode?=?Portrait; ????else ????????currentscreenMode?=?Landscape; ? ????if?(currentscreenMode!=scmode) ????{ ????????scmode?=?currentscreenMode; ????????switch(scmode) ????????{ ????????case?Portrait: ????????????this->setStyleSheet("QMainWindow{?background-image:?url(:/pics/bgPortrait.jpg)}"); ????????????break; ????????case?Landscape: ????????????this->setStyleSheet("QMainWindow{?background-image:?url(:/pics/bgLandscape.jpg)}"); ????????????break; ????????default: ????????????break; ????????} ????} }