1. 程式人生 > >零基礎學Qt 4程式設計例項之Qt 樣式表的應用

零基礎學Qt 4程式設計例項之Qt 樣式表的應用

下面我們以一個例項來講解樣式表的應用。這個例子取材於Qt Demo,比較複雜,有一定難度,基本上覆蓋了前面幾章講述的各種技能點,主要包括:

◆ 如何自定義Qt 的樣式表

◆ 如何在應用程式中應用樣式表

◆ 如何不使用樣式表來設定應用程式的樣式

◆ 如何使用單繼承法從.ui檔案建立派生類

◆ 如何自定義資源集檔案

◆ 如何使訊號和槽自動連線

◆ 如何在兩個視窗之間建立關聯

◆ 元物件系統方法的使用

這個程式名字叫stylesheet,其執行後的效果如圖9-17所示。

9-17 例項執行效果

該例子基於主視窗樣式,有些類似於我們在網上所常見的填寫個人資料的網站註冊程式。

程式有兩個主選單,依次點選【File

->Edit Style】選單項,將彈出如圖9-18所示的設定樣式表的對話方塊,在其中內建了幾種樣式供選擇,使用者也可以在編輯框中輸入自定義的樣式。設定完成後,主介面的視窗部件的樣式將依此相應的變化。裡面的Coffee樣式自定義了push buttonframestooltip,但使用了下層的風格 (例如這裡是Windows XP風格)來繪製checkboxcomboboxradio buttonPagefold風格完全重新定義了對話方塊中使用的所有控制元件的外觀,從而實現了一種獨特的,平臺無關的外觀。

9-18 樣式表編輯器

這個程式裡面包含如下原生原始檔:

mainwindow.ui

stylesheeteditor.ui

stylesheet.qrc

/qss/coffee.qss

/qss/default.qss

/qss/pagefold.qss

/images/*.png

mainwindow.h

mainwindow.cpp

stylesheeteditor.h

stylesheeteditor.cpp

其中,mainwindow.uistylesheeteditor.ui分別是主程式和樣式編輯器的介面佈局檔案,是使用Qt Designer製作的。Stylesheet.qrc是資源集檔案,在其中描述了程式中用到的樣式表文件和圖片檔案的位置和名稱。在qss

資料夾中包含了3.qss檔案,它們描述了程式中用到的樣式,我們的程式將讀取它們並轉換成樣式表。在images資料夾中放置了程式中用到的圖片檔案。mainwindow.hmainwindow.cpp構成了程式中的主程式類,而stylesheeteditor.hstylesheeteditor.cpp構成了樣式編輯器類。

下面我們就結合原始碼為大家講解這個程式的功能是怎樣實現的。

首先看看mainwindow.h

1#ifndef MAINWINDOW_H
2#define MAINWINDOW_H
3#include <QtGui>
4#include "ui_mainwindow.h"
5class StyleSheetEditor;
6class MainWindow : public QMainWindow
{
7Q_OBJECT
8public:
9MainWindow();
10private slots:
11void on_editStyleAction_triggered();
12void on_aboutAction_triggered();
13private:
14StyleSheetEditor *styleSheetEditor;
15Ui::MainWindow ui;
};
16#endif

12和第16行一起構成了標頭檔案的預定義衛哨,這樣做的目的是為了防止程式中重複定義或包含標頭檔案,是嚴謹的程式設計風格,建議大家遵循這一範例的做法。

3行引入QtGui模組的宣告,它包含了QMainWindow類的定義。

4行引入ui_mainwindow.h的宣告。

5行採用前置宣告的方式引入樣式編輯器類StyleSheetEditor

6行宣告主程式類MainWindow單公有繼承自QMainWindow類。

7行時必需的,因為要用到Qt的核心機制,如訊號/槽機制等。

89行宣告MainWindow類的建構函式。

10-12行宣告私有槽,它們的命名遵循了Qt訊號/槽的“自動關聯規則”。

13-15行聲明瞭私有成員,它們分別是樣式編輯器類的物件和主程式介面類的物件。從這裡也可以看出,我們對.ui檔案的引入將採用單繼承的方式。

下面再來看一下mainwindow.cpp檔案的內容。

1#include "mainwindow.h"
2#include "stylesheeteditor.h"
3MainWindow::MainWindow()
{
4ui.setupUi(this);
5ui.nameLabel->setProperty("class", "mandatory QLabel");
6styleSheetEditor = new StyleSheetEditor(this);
7statusBar()->addWidget(new QLabel(tr("Ready")));
8connect(ui.exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
9connect(ui.aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}
10void MainWindow::on_editStyleAction_triggered()
{
11styleSheetEditor->show();
12styleSheetEditor->activateWindow();
}
13void MainWindow::on_aboutAction_triggered()
{
14QMessageBox::about(this, tr("About Style sheet"),
tr("The <b>Style Sheet</b> example shows how widgets can be styled "
"using <a href=/"http://doc.trolltech.com/4.5/stylesheet.html/">Qt "
"Style Sheets</a>. Click <b>File|Edit Style Sheet</b> to pop up the "
"style editor, and either choose an existing style sheet or design "
"your own."));
}

12兩行引入程式中用到的標頭檔案宣告。

4行初始化介面佈局,setupUi()函式一般要放在建構函式內的第一行。

5行設定nameLabel的屬性,setProperty()方法的原型如下:

bool QObject::setProperty ( const char * name, const QVariant & value )

它將物件的name的屬性值設定為 value。對於本句來說,就是把nameLabelclass屬性值設定為"mandatory QLabel"這將使得該視窗部件被突出顯示。

6行例項化styleSheetEditor類的物件,其父視窗為MainWindow

7行為狀態列新增一個視窗部件,顯示"Ready"字樣,即漢語的“就緒“

89行分別連線選單項exitActionaboutQtAction的觸發訊號triggered()和全域性物件qAppquit()槽和aboutQt()槽。

10-12行定義了on_editStyleAction_triggered()槽函式。

11行顯示樣式編輯器視窗。

12行呼叫activateWindow()方法把樣式編輯器視窗設定為活動視窗。activateWindow()方法的原型如下:

void QWidget::activateWindow ()

它用來把某個頂層視窗設定為當前的活動視窗。

小貼士:活動視窗與如何設定活動視窗

所謂活動視窗就是當前能夠擁有鍵盤輸入焦點的,可見的頂層視窗。

activateWindow()方法的作用與用滑鼠單擊頂層視窗的標題欄的效果是一樣的。在X11上,這個效果並不確定,因為它依賴於具體的視窗管理器,如果要確保某視窗為活動視窗,最好是在呼叫activateWindow()方法之後再呼叫raise()方法,後者本身也是Qt內建的一個槽函式。但無論如何,在這之前都需要確保該視窗首先是可見的,否則將沒有任何效果。

Windows平臺上,這種情形又有些差異。因為Microsoft不允許一個應用打斷由另一個應用建立起來的和使用者的對話(即互動過程),所以activateWindow()被呼叫後,該視窗部件可能還是不能成為頂層的活動視窗,而只是它的標題欄變為高亮,以告訴使用者該視窗部件的狀態發生了某些變化。這一點,請讀者朋友在使用時注意。

如果想知道某視窗是否為活動視窗,可以呼叫方法。

前面我們曾經講到過Qt核心機制中的“資源集檔案“。現在我們看一下如何在Qt Creator中書寫或配置資源集檔案。

Qt Creator中用滑鼠雙擊資源集檔案,將開啟資源集檔案編輯器,在資源集編輯器中可以增加或刪除檔案、節點等,其操作比較方便,一目瞭然。如圖9-19所示。

9-19 資源集檔案編輯器

我們再來看一下stylesheeteditor.h檔案的內容。

#ifndef STYLESHEETEDITOR_H
#define STYLESHEETEDITOR_H
#include <QDialog>
#include "ui_stylesheeteditor.h"
1class StyleSheetEditor : public QDialog
{
2Q_OBJECT
3public:
4StyleSheetEditor(QWidget *parent = 0);
5private slots:
6void on_styleCombo_activated(const QString &styleName);
7void on_styleSheetCombo_activated(const QString &styleSheetName);
8void on_styleTextEdit_textChanged();
9void on_applyButton_clicked();
10private:
11void loadStyleSheet(const QString &sheetName);
12Ui::StyleSheetEditor ui;
};
13#endif

1行宣告StyleSheetEditor類單公有繼承自QDialog

5-9行聲明瞭程式中的私有槽,命名遵循了Qt訊號/槽的“自動關聯規則”。

11行聲明瞭私有方法loadStyleSheet(),它用來從.qss檔案中讀取內容並轉化問樣式表。

12行聲明瞭私有成員變數ui

再來看一下stylesheeteditor.cpp

#include <QtGui>
#include "stylesheeteditor.h"
1StyleSheetEditor::StyleSheetEditor(QWidget *parent)
: QDialog(parent)
{
2ui.setupUi(this);
3QRegExp regExp(".(.*)//+?Style");
4QString defaultStyle = QApplication::style()->metaObject()->className();
5if (regExp.exactMatch(defaultStyle))
{
6defaultStyle = regExp.cap(1);
}
7ui.styleCombo->addItems(QStyleFactory::keys());
8ui.styleCombo->setCurrentIndex(ui.styleCombo->findText(defaultStyle, Qt::MatchContains));
9ui.styleSheetCombo->setCurrentIndex(ui.styleSheetCombo->findText("Coffee"));
10loadStyleSheet("Coffee");
}
11void StyleSheetEditor::on_styleCombo_activated(const QString &styleName)
{
12qApp->setStyle(styleName);
13ui.applyButton->setEnabled(false);
}
14void StyleSheetEditor::on_styleSheetCombo_activated(const QString &sheetName)
{
15loadStyleSheet(sheetName);
}
16void StyleSheetEditor::on_styleTextEdit_textChanged()
{
17ui.applyButton->setEnabled(true);
}
18void StyleSheetEditor::on_applyButton_clicked()
{
19qApp->setStyleSheet(ui.styleTextEdit->toPlainText());
20ui.applyButton->setEnabled(false);
}
21void StyleSheetEditor::loadStyleSheet(const QString &sheetName)
{
22QFile file(":/qss/" + sheetName.toLower() + ".qss");
23file.open(QFile::ReadOnly);
24QString styleSheet = QLatin1String(file.readAll());
25ui.styleTextEdit->setPlainText(styleSheet);
26qApp->setStyleSheet(styleSheet);
27ui.applyButton->setEnabled(false);
}

3-6行呼叫Qt中的正則表示式來取得預設的樣式。

3行定義一個正則表示式變數regExp

首先通過style()方法獲得應用程式的樣式,然後利用Qt元物件機制獲取元物件資訊。style()方法是QApplication類的靜態方法,其原型如下:

QStyle * QApplication::style ()   [static]

它將返回應用程式的樣式物件。

這裡簡單的講解一下Qt元物件機制,詳細的內容請見第13章。

Qt的元物件系統是Qt的核心機制之一,Qt的訊號/槽機制、屬性系統、執行時型別資訊等機制都是以元物件系統為基礎的。在應用程式中,每一個QObject的子類都會有一個單獨的Qt元物件例項,這個例項中儲存了該類所有的元物件資訊,該例項可以通過呼叫QObject::metaObject()方法來得到。

QMetaObject被稱作是Qt的元物件類,它包含了Qt物件的元資訊。

QObject::metaObject()方法的原型如下:

const  * QObject::metaObject () const   [virtual]

可以看到,它返回本物件的指向其元物件的指標。

用來獲取元物件資訊的方法有很多,本程式中用到的className()是其中的一種,它返回類的名字。

56兩行應用正則表示式的校驗來獲得defaultStyle的值。

8行是為styleCombo設定當前下拉框列表中的預設選項。findText()QcomboBox類的方法,其原型如下:

int QComboBox::findText ( const QString & textQt::MatchFlags flags = Qt::MatchExactly | Qt::MatchCaseSensitive ) const

它在QComboBox物件的item列表中搜索與text相匹配的項的索引值,如果沒有相匹配的項,則返回-1,該值是int型的。flags引數給出了搜尋的方法,即如何與text相匹配。flags的值取自列舉值Qt::MatchFlag,後者描述了在一個模型中搜索時可以遵循的匹配原則,如表9-2所示。

9-2 MatchFlag的取值

常量

說明

Qt::MatchExactly

0

執行QVariant匹配(QVariant可以看做是Qt的最常用變數型別的聯合體)

Qt::MatchFixedString

8

執行按字元匹配。注意這種方式預設情況下不區分大小寫,只有同時指定Qt::MatchCaseSensitive 才區分大小寫。

Qt::MatchContains

1

搜尋條件包含在(QComboBox的下拉列表)專案中

Qt::MatchStartsWith

2

匹配條件是與項的開頭相匹配,即“以XXX開頭”

Qt::MatchEndsWith

3

搜尋的條件與項的結尾相匹配,即“以XXX為結尾”

Qt::MatchCaseSensitive

16

執行大小寫敏感匹配搜尋

Qt::MatchRegExp

4

以一個正則表示式為匹配條件執行按字元匹配搜素,注意這種方式不區分大小寫,除非同時指定Qt::MatchCaseSensitive 條件。

Qt::MatchWildcard

5

Qt::MatchWrap

32

執行類似“令牌環”式的搜尋,對每一個項都要經過驗證

Qt::MatchRecursive

64

執行遞迴搜尋

所有上述這些標記符號都是QFlags< MatchFlag >的一部分,它們之間的組合可以用OR來連線,在程式中即是使用|符號。這些標記符號經常與QRegExp類結合使用。

9行與第8行同理,設定styleSheetCombo的當前項為Coffee,也即當前的樣式表的名稱為Coffee

緊接著,第10行呼叫loadStyleSheet()方法相應的設定應用程式的樣式表為Coffee

21-27行是loadStyleSheet()方法的定義。

22行使用QFile類的物件根據實參取得Coffee樣式表對應的.qss檔案全名,即帶路徑的Coffee.qss

23行以只讀方式開啟Coffee.qss檔案。

24行讀取檔案的全部內容。QLatin1String類的建構函式原型如下:

QLatin1String::QLatin1String ( const char * str )

相關推薦

基礎Qt 4程式設計例項Qt 樣式應用

下面我們以一個例項來講解樣式表的應用。這個例子取材於Qt Demo,比較複雜,有一定難度,基本上覆蓋了前面幾章講述的各種技能點,主要包括: ◆ 如何自定義Qt 的樣式表 ◆ 如何在應用程式中應用樣式表 ◆ 如何不使用樣式表來設定應用程式的樣式 ◆ 如何使用單繼承法從.ui檔案

基礎python-4.2 其它內建類型

介紹 src one 一個 tex == water 文件 div 這一章節我們來聊聊其它內建類型 1.類型type 在python2.2的時候,type是通過字符串實現的,再後來才把類型和類統一 我們再次使用上一章節的圖片來說明一些問題 我們通

基礎Qt 4程式設計中心視窗部件的使用總結

Qt程式中的主視窗通常具有一箇中心視窗部件。從理論上來講,任何繼承自QWidget的類的派生類的例項,都可以作為中心視窗部件使用。 幾種常見情形 QMainWindow的中心區域可以被任意種類的視窗部件所佔用。下面給出的是可能的情形。 ⒈ 使用標準的Qt視窗部件(

基礎Qt 4程式設計》準備再版,近期重印。請大家提寶貴意見,謝謝。

如題。接到出版社編輯通知,《零基礎學Qt 4程式設計》第一版即將售罄,準備再版。 近期先準備重印。我已經收集了我自己發現的,以及朋友們提到的書中的錯誤,準備在重印前改正。 如果大家有對這本書的意見和建議,比如章節的安排,內容的選擇,等等都可以想我提出,通過本站簡訊或我的

基礎c語言循環

零基礎 png http 一點 堅持 alt 另一個 col 無奈 記錄每一天的學習,從零到一。堅持與你我同在。   看了很多的書,仍然不會編程,從進入一個坑在到另一個坑中。其實很無奈,但也沒辦法。 也許,你需要一點好的思考過程。時間只會讓我們記住那些難忘的事。那些過眼雲煙

基礎c語言比較數

inf 比較大小 bubuko 輸出最大值 根據 過多 圖片 turn 簡單的 我們通常會遇到比較幾個數的大小的問題。具體來說是比較大小後將兩個數交換,但是有人通過if(a>b)[printf("%d",a)} else {printf("%d",b)}的方式避開

基礎Java程式設計開發要會這些知識才能去應聘工作!

Java行業在網際網路發展迅速的今天是一日比一日發展的好,Java語言已經成為世界上應用較廣泛的程式語言,學Java已經成為程式語言中的潮流,越來越多的人有意向到Java行業中發展。那零基礎如何學習Java開發?要會什麼? Java其實就是計算機程式語言,初級程式設計師具備一點點的資料結構知識以

中國大學MOOC 基礎Java語言 ——多項式加法(5分) 4分答案(想哭)

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int x =

10歲小孩通過程式設計成為CEO,基礎IT真的不難

一名6歲開始學習程式設計的小朋友,10歲就成為了一名被全矽谷追捧的女程式設計師,同時她還兼任了一家遊戲公司的CEO。扎克伯格贊她未來可期,奧巴馬伕人還親自寫信鼓勵她,這名美國小女孩叫沙邁拉·梅塔。   她6歲的時候對程式語言產生了興趣,於是每天纏著工程師爸爸教她學計算機知識,7歲的時候,她已

基礎Java10系列三:Java高階程式設計​​​​​​​

多執行緒:  生產者和消費者指的是兩個不同的執行緒類物件,兩個程序公用一個公共的固定大小緩衝區。其中之一的生產者,用於將訊息傳入緩衝區,另外一個是消費者,用於從緩衝區取    出資料。當緩衝區滿了,而此時生產者還想向其中放入新的資料,其解決方法是讓生產者此時進行休眠,等待消費

基礎UI設計教程圖示的設計形式講解

這次的總結主要內容是從圖示這一方面作為切入點來進行一些分析。整體內容剛好契合了最近的學習重點,自己也越來越肯定設計師在發展的中後期設計思路比技術手法的重要性。自己的這次總結希望能傳遞一個思路,或者是能夠讓大家有一點點更好的思考方式。 這次對比主要選擇了QQ、淘寶、微博三款最常用APP為主線分析,輔助以快手、

基礎Java10系列一:程式設計入門

本課程主要講解JavaSE的發展歷史,JDK開發環境的搭建,CLASSPATH屬性作用,Java程式基本結構、基本資料型別的劃分及使用、程式結構、方法的定義與使用。本課程是作為Java系列課程的初期課程,掌握本課程之後可以繼續學習Java面向物件程式設計及高階開發部分。

中國大學MOOC 基礎Java語言 ——多項式加法(5分) 4分答案(想哭)

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in);

基礎程式設計難嗎?哪種程式語言最好?

作為使用最廣泛的程式語言、以及市場上java人才的需求越來越大,很多人都準備報java培訓班轉行IT,可是對於很多新手來說,剛開始接觸Java會很迷惘,只知道跟風報班學習,卻不知道Java可以做什麼。 其實Java 可以做的東西太多了,手機遊戲、中介軟體、軟體、

基礎程式設計找好大腿很重要!

相信各位同學在學習java的時候會遇到很多問題,其實不管是參加培訓,還是自學,有一個好老師(前輩)很重要,一定要找一個好的,有經驗的老師(我們稱之為大腿)。至於怎麼去找這樣的人,大家就只能靠自己啦。IT君今天講的一些東西也都是是建立在有人帶你(指導)的基礎上。

基礎Java語言(第三週程式設計題)

1奇偶個數(5分) 題目內容: 你的程式要讀入一系列正整數資料,輸入-1表示輸入結束,-1本身不是輸入的資料。程式輸出讀到的資料中的奇數和偶數的個數。 輸入格式: 一系列正整數,整數的範圍是(0,100000)。如果輸入-1則表示輸入結束。 輸出格式: 兩個整數,第一個整數表

基礎Java語言(第二週程式設計題)

1時間換算(5分) 題目內容: UTC是世界協調時,BJT是北京時間,UTC時間相當於BJT減去8。現在,你的程式要讀入一個整數,表示BJT的時和分。整數的個位和十位表示分,百位和千位表示小時。如果小時小於10,則沒有千位部分;如果小時是0,則沒有百位部分;如果分小於10分,需要保留十位上的

分解質因數——MOOC《基礎Java語言》第7周程式設計題1

題目內容:每個非素數(合數)都可以寫成幾個素數(也可稱為質數)相乘的形式,這幾個素數就都叫做這個合數的質因數。比如,6可以被分解為2x3,而24可以被分解為2x2x2x3。現在,你的程式要讀入一個[2,100000]範圍內的整數,然後輸出它的質因數分解式;當讀到的就是素數時,輸出它本身。輸入格式:一個整數,範

基礎FPGA(十二)一步一腳印基於FIFO的串列埠傳送機設計全流程及常見錯誤詳解

     今天要寫的是一段基於FIFO的串列埠傳送機設計,之前也寫過串列埠傳送的電路,這次寫的與上次的有幾分類似。這段程式碼也是我看過別人寫過的之後,消化一下再根據自己的理解寫出來的,下面是我寫這段程式碼的全部流程和思路,希望對剛開始接觸的朋友來說有一點點的幫助,也希望有

基礎Java10系列二:面向物件程式設計

面向過程與面向物件都是我們程式設計中,編寫程式的一種思維方式。 面向過程的程式設計方式,是遇到一件事時,思考“我該怎麼做”,然後一步步實現的過程。 面向物件的程式設計方式,是遇到一件事時,思考“我該讓誰來做”,然後那個“誰”就是物件,他要怎麼做這件事是他自己的事,反正最後