2.概覽
本章將介紹如果開(kāi)始使用 Qt 5 進(jìn)行開(kāi)發(fā)。將展示如何安裝 Qt SDK,以及如何使用 Qt Creator IDE 創(chuàng)建以及運(yùn)行一個(gè)簡(jiǎn)單的 hello world 應(yīng)用程序。
提示
本章的源代碼可以在這里下載。
2.1.安裝 Qt 5 SDK
Qt軟件工具包包含了編譯桌面或者嵌入式應(yīng)用程序的工具。最新的版本可以從Qt-Project 主頁(yè)下載。我們將使用這種方法開(kāi)始。軟件工具包自身包含了一個(gè)維護(hù)工具允許你更新到最新版本的軟件工具包。
Qt 軟件工具包非常容易安裝,并且附帶了一個(gè)它自身的快速集成開(kāi)發(fā)環(huán)境叫做 Qt Creator。這個(gè)集成開(kāi)發(fā)環(huán)境可以讓你高效的使用 Qt 進(jìn)行開(kāi)發(fā),我們推薦給所有的讀者使用。在任何況下 Qt 都可以通過(guò)命令的方式來(lái)編譯,你可以自由的選擇你的代碼編輯器。
當(dāng)我們開(kāi)始安裝 SDK 時(shí),最好選擇默認(rèn)的選項(xiàng)確保 Qt 5.x 可以使用。然后一切準(zhǔn)備就緒。
2.2.編寫(xiě)示例程序
為了測(cè)試我們的安裝是否成功,我們可以創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用程序 hello world。打開(kāi) Qt Creator 并且創(chuàng)建一個(gè) Qt Quick UI Project(File -> New File 或者 Project -> Qt Quick Project -> Qt Quick UI)并且給項(xiàng)目取名 HelloWorld。
提示:
Qt Creator 集成開(kāi)發(fā)環(huán)境允許我們創(chuàng)建不同類型的應(yīng)用程序。如果沒(méi)有特別說(shuō)明,我們都將默認(rèn)創(chuàng)建 Qt Quick UI Project 項(xiàng)目。
提示:
典型的 Qt Quick 應(yīng)用程序是由稱為 QmlEngine 的運(yùn)行時(shí)進(jìn)行加載的,它加載初始的 QML 代碼。 開(kāi)發(fā)人員可以使用運(yùn)行時(shí)注冊(cè)的 C++ 類型以與本地代碼進(jìn)行接口交互。這些 C++ 類型也可以綁定到一個(gè)插件中,然后使用 import 語(yǔ)句來(lái)動(dòng)態(tài)加載。qmlscene 和 qml 工具是預(yù)制的運(yùn)行時(shí)庫(kù),可以在 QML 中直接使用。一開(kāi)始我們不會(huì)介紹本地化的代碼開(kāi)發(fā)知識(shí),我們將只關(guān)注 Qt 5 的 QML 方面的知識(shí)。
Qt Creator 將會(huì)為我們自動(dòng)地創(chuàng)建幾個(gè)文件。HellWorld.qmlproject 文件是項(xiàng)目文件,保存了項(xiàng)目的配置信息。這個(gè)文件由 Qt Creator 管理,我們不需要編輯它。
另一個(gè)文件 HelloWorld.qml 是我們的應(yīng)用程序代碼。打開(kāi)它并嘗試看看應(yīng)用我們這個(gè)程序的作用,然后繼續(xù)閱讀。
// HelloWorld.qml
import QtQuick 2.0
Rectangle {
width: 360
height: 360
Text {
anchors.centerIn: parent
text: "Hello World"
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
}
這個(gè) HelloWord.qml 是用 QML 語(yǔ)言編寫(xiě)的。我們將在下一章中更深入地討論 QML 語(yǔ)言。上面的代碼的意思是在一系列分層元素中描述了用戶界面:該代碼顯示了一個(gè) 360 x 360 像素的矩形,居中顯示了內(nèi)容為 “Hello World” 的文本元素,鼠標(biāo)監(jiān)聽(tīng)區(qū)域覆蓋整個(gè)矩形區(qū)域,當(dāng)用戶點(diǎn)擊它時(shí),應(yīng)用程序退出。
接下來(lái),我們可以點(diǎn)擊
按鈕或者從菜單選擇 Bulid->Run 運(yùn)行上面的代碼。
Qt Creator 將啟動(dòng) qmlscene,并將 QML 文檔作為第一個(gè)參數(shù)傳遞。 qmlscene 將解析文檔并啟動(dòng)用戶界面?,F(xiàn)在我們應(yīng)該可以看到下面這樣的應(yīng)用界面:

Qt 5 似乎在正常地工作,我們繼續(xù)下面的內(nèi)容吧。
建議
如果您是系統(tǒng)集成商,您將需要安裝 Qt SDK 以獲取最新的穩(wěn)定的 Qt 版本以及根據(jù)特定設(shè)備目標(biāo)的源代碼編譯的 Qt 版本。
從頭開(kāi)始構(gòu)建
如果要從命令行構(gòu)建 Qt 5,首先需要獲取代碼存儲(chǔ)庫(kù)的副本并構(gòu)建它。
git clone git://gitorious.org/qt/qt5.git
cd qt5
./init-repository
./configure -prefix $PWD/qtbase -opensource
make -j4
在成功匯編和喝完2杯咖啡之后,Qt 5 將在 qtbase 文件夾中編譯完成。其實(shí)喝任何飲料都行的,但是,我們建議喝咖啡以獲得最佳效果。
如果要測(cè)試您的編譯是否成功,只需啟動(dòng) qtbase/bin/qmlscene 并選擇一個(gè) Qt Quick 示例來(lái)運(yùn)行它......或隨我們進(jìn)入下一章。
為了測(cè)試我們的安裝,我們可以創(chuàng)建一個(gè)小的 hello world 應(yīng)用程序??梢允褂梦覀兿矚g的文本編輯器創(chuàng)建一個(gè)簡(jiǎn)單的 example.qml 文件,然后粘貼以下內(nèi)容:
// HelloWorld.qml
import QtQuick 2.5
Rectangle {
width: 360
height: 360
Text {
anchors.centerIn: parent
text: "Greetings from Qt 5"
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
}
我們使用如下命令并通過(guò) Qt 5 附帶的默認(rèn)運(yùn)行環(huán)境運(yùn)行示例:
qtbase/bin/qmlscene
2.3.應(yīng)用程序類型
本節(jié)將介紹一些可能使用 Qt 5 編寫(xiě)的不同應(yīng)用程序類型。它不僅限于所提供的這些內(nèi)容,但這些應(yīng)該可以讓讀者更好地了解 Qt 5 的一般功能。
2.3.1.控制臺(tái)應(yīng)用程序
控制臺(tái)應(yīng)用程序不提供任何圖形用戶界面,通常將其作為系統(tǒng)服務(wù)或通過(guò)命令行進(jìn)行調(diào)用。Qt 5 附帶了一系列現(xiàn)成的組件,可幫助我們非常有效地創(chuàng)建控制臺(tái)跨平臺(tái)應(yīng)用程序。例如網(wǎng)絡(luò)文件API、字符串處理、以及自 Qt 5.1 起提供的高效命令行解析器。由于 Qt 是基于 C++ 的高級(jí)應(yīng)用程序接口,我們能夠快速的編程并且程序擁有快速的執(zhí)行速度。不要把 Qt 僅僅當(dāng)作是一個(gè) UI 工具包——它其實(shí)能幫助我們做更多的事。
字符串處理
在第一個(gè)例子中我們展示了怎樣簡(jiǎn)單的增加兩個(gè)字符串常量。這不是一個(gè)有用的應(yīng)用程序,但能讓我們了解沒(méi)有事件循環(huán)的本地端 C++ 應(yīng)用程序的大概模樣。
// module or class includes
#include <QtCore>
// text stream is text-codec aware
QTextStream cout(stdout, QIODevice::WriteOnly);
int main(int argc, char** argv)
{
// avoid compiler warnings
Q_UNUSED(argc)
Q_UNUSED(argv)
QString s1("Paris");
QString s2("London");
// string concatenation
QString s = s1 + " " + s2 + "!";
cout << s << endl;
}
容器類
這個(gè)例子在應(yīng)用程序中增加了一個(gè)鏈表和一個(gè)鏈表迭代器。Qt 自帶大量方便使用的容器類,并且其中的元素使用相同的應(yīng)用程序接口模式。
QString s1("Hello");
QString s2("Qt");
QList<QString> list;
// stream into containers
list << s1 << s2;
// Java and STL like iterators
QListIterator<QString> iter(list);
while(iter.hasNext()) {
cout << iter.next();
if(iter.hasNext()) {
cout << " ";
}
}
cout << "!" << endl;
下面我們顯示一些高級(jí)列表功能,它允許我們將字符串列表加入到一個(gè)字符串中。 當(dāng)您需要繼續(xù)進(jìn)行基于行的文本輸入時(shí),這非常方便。使用 QString::split() 函數(shù)可以將這個(gè)操作進(jìn)行逆向處理(將字符串轉(zhuǎn)換為字符串鏈表)。
QString s1("Hello");
QString s2("Qt");
// convenient container classes
QStringList list;
list << s1 << s2;
// join strings
QString s = list.join(" ") + "!";
cout << s << endl;
文件 IO
在下一個(gè)片段中,我們從本地目錄中讀取一個(gè)CSV文件,并循環(huán)遍歷行,以從每行中提取內(nèi)容。為了做到這一點(diǎn),我們需要從CSV文件中獲取大約20行的編碼。文件讀取只給我們一個(gè)字節(jié)流,能夠?qū)⑵滢D(zhuǎn)換成一個(gè)有效的 Unicode 文本,我們需要使用文本流,并將文件作為較低級(jí)別的流傳遞。對(duì)于編寫(xiě)CSV文件,我們只需要在寫(xiě)入模式下打開(kāi)文件,并將文本一行一行地輸入到文本流中。
QList<QStringList> data;
// file operations
QFile file("sample.csv");
if(file.open(QIODevice::ReadOnly)) {
QTextStream stream(&file);
// loop forever macro
forever {
QString line = stream.readLine();
// test for null string 'String()'
if(line.isNull()) {
break;
}
// test for empty string 'QString("")'
if(line.isEmpty()) {
continue;
}
QStringList row;
// for each loop to iterate over containers
foreach(const QString& cell, line.split(",")) {
row.append(cell.trimmed());
}
data.append(row);
}
}
// No cleanup necessary.
至此,關(guān)于使用 Qt 進(jìn)行控制臺(tái)應(yīng)用程序的編寫(xiě)介紹就告一段落。
2.3.2.窗口應(yīng)用程序
基于控制臺(tái)的應(yīng)用程序非常方便,但有時(shí)您需要有一個(gè) UI 來(lái)顯示。 此外,基于 UI 的應(yīng)用程序可能需要后端來(lái)讀/寫(xiě)文件,通過(guò)網(wǎng)絡(luò)進(jìn)行通信,或?qū)?shù)據(jù)保存在容器中。
在第一個(gè)窗口應(yīng)用程序片段中,我們根據(jù)需要盡可能少地創(chuàng)建一個(gè)窗口并顯示它。沒(méi)有父對(duì)象的窗口部件是 Qt 世界中的一個(gè)窗口。我們使用智能指針來(lái)確保當(dāng)智能指針指向范圍外時(shí)窗口會(huì)被刪除掉。應(yīng)用程序?qū)ο蠓庋b了 Qt 運(yùn)行時(shí)庫(kù),并且通過(guò)調(diào)用 exec() 啟動(dòng)事件循環(huán)。應(yīng)用程序只能對(duì)鼠標(biāo)、鍵盤(pán)或者其他事件提供程序(如網(wǎng)絡(luò)或文件 IO)觸發(fā)的事件發(fā)生響應(yīng)。當(dāng)退出事件循環(huán)時(shí),應(yīng)用程序才會(huì)退出。這可以通過(guò)在應(yīng)用程序上調(diào)用 quit() 或關(guān)閉窗口來(lái)完成。
當(dāng)我們運(yùn)行代碼時(shí),我們將看到一個(gè)大小為 240 x 120 像素的空白窗口。
#include <QtGui>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QScopedPointer<QWidget> widget(new CustomWidget());
widget->resize(240, 120);
widget->show();
return app.exec();
}
自定義窗口部件
當(dāng)使用用戶界面時(shí),我們可能需要?jiǎng)?chuàng)建自定義的窗口部件。 通常,窗口部件是一個(gè)填充繪制的窗口區(qū)域。另外,窗口部件具有如何處理鍵盤(pán)或鼠標(biāo)輸入以及如何對(duì)外部觸發(fā)器做出反應(yīng)的內(nèi)部知識(shí)。為了在 Qt 中做這些,我們需要從 QWidget 派生并覆蓋繪畫(huà)和事件處理的幾個(gè)函數(shù)。
#ifndef CUSTOMWIDGET_H
#define CUSTOMWIDGET_H
#include <QtWidgets>
class CustomWidget : public QWidget
{
Q_OBJECT
public:
explicit CustomWidget(QWidget *parent = 0);
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
QPoint m_lastPos;
};
#endif // CUSTOMWIDGET_H
在實(shí)現(xiàn)中,我們?cè)诖翱诓考侠L制一個(gè)小邊框,并在最后一個(gè)鼠標(biāo)位置上繪制一個(gè)小矩形。這對(duì)于低級(jí)別的自定義窗口部件是非常典型的。鼠標(biāo)或鍵盤(pán)事件會(huì)更改窗口部件的內(nèi)部狀態(tài)并觸發(fā)繪畫(huà)更新。我們不會(huì)在這段代碼中詳細(xì)介紹,但是希望你知道我們有這個(gè)能力。Qt 帶有一大批現(xiàn)成的桌面小部件,因此我們不必自定義窗口部件的概率很高。
#include "customwidget.h"
CustomWidget::CustomWidget(QWidget *parent) :
QWidget(parent)
{
}
void CustomWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QRect r1 = rect().adjusted(10,10,-10,-10);
painter.setPen(QColor("#33B5E5"));
painter.drawRect(r1);
QRect r2(QPoint(0,0),QSize(40,40));
if(m_lastPos.isNull()) {
r2.moveCenter(r1.center());
} else {
r2.moveCenter(m_lastPos);
}
painter.fillRect(r2, QColor("#FFBB33"));
}
void CustomWidget::mousePressEvent(QMouseEvent *event)
{
m_lastPos = event->pos();
update();
}
void CustomWidget::mouseMoveEvent(QMouseEvent *event)
{
m_lastPos = event->pos();
update();
}
桌面窗口部件
Qt 開(kāi)發(fā)人員已經(jīng)為您完成了所有這些工作,并提供了一組桌面小部件,它們將在不同的操作系統(tǒng)上看起來(lái)很像是原生的窗口部件。然后,我們的工作就是將部件容器中的這些不同的部件排列成更大的面板。Qt中的小部件也可以是其他小部件的容器。這是通過(guò)親子關(guān)系來(lái)實(shí)現(xiàn)的。。這意味著我們需要準(zhǔn)備類似按鈕(button),復(fù)選框(check box),單選按鈕(radio button)的窗口部件并且對(duì)它們進(jìn)行布局。完成此操作的一種方法如下所示。
這是一個(gè)所謂的 widget 容器的頭文件。
class CustomWidget : public QWidget
{
Q_OBJECT
public:
explicit CustomWidget(QWidget *parent = 0);
private slots:
void itemClicked(QListWidgetItem* item);
void updateItem();
private:
QListWidget *m_widget;
QLineEdit *m_edit;
QPushButton *m_button;
};
在實(shí)現(xiàn)中,我們使用布局來(lái)更好地安排我們的小部件。 當(dāng)容器小部件重新調(diào)整大小時(shí),布局管理器會(huì)根據(jù)某些大小策略重新布置小部件。在這個(gè)例子中,我們有一個(gè)列表,一個(gè)行編輯和一個(gè)垂直排列的按鈕,可以編輯城市列表。我們使用 Qt 的信號(hào)和槽來(lái)連接發(fā)送器和接收器對(duì)象。
CustomWidget::CustomWidget(QWidget *parent) :
QWidget(parent)
{
QVBoxLayout *layout = new QVBoxLayout(this);
m_widget = new QListWidget(this);
layout->addWidget(m_widget);
m_edit = new QLineEdit(this);
layout->addWidget(m_edit);
m_button = new QPushButton("Quit", this);
layout->addWidget(m_button);
setLayout(layout);
QStringList cities;
cities << "Paris" << "London" << "Munich";
foreach(const QString& city, cities) {
m_widget->addItem(city);
}
connect(m_widget, SIGNAL(itemClicked(QListWidgetItem*)),
this, SLOT(itemClicked(QListWidgetItem*)));
connect(m_edit, SIGNAL(editingFinished()), this, SLOT(updateItem()));
connect(m_button, SIGNAL(clicked()), qApp, SLOT(quit()));
}
void CustomWidget::itemClicked(QListWidgetItem *item)
{
Q_ASSERT(item);
m_edit->setText(item->text());
}
void CustomWidget::updateItem()
{
QListWidgetItem* item = m_widget->currentItem();
if(item) {
item->setText(m_edit->text());
}
}
繪制圖形
有一些問(wèn)題最好用可視化的方式表達(dá)。如果手邊的問(wèn)題看起來(lái)有點(diǎn)像幾何對(duì)象,qt graphics view 是一個(gè)很好的選擇。一個(gè)圖形視窗(graphics view)能夠在一個(gè)場(chǎng)景(scene)排列簡(jiǎn)單的幾何圖形。用戶可以與這些圖形交互,它們使用一定的算法放置在場(chǎng)景(scene)上。填充一個(gè)圖形視圖你需要一個(gè)圖形窗口(graphics view)和一個(gè)圖形場(chǎng)景(graphics scene)。一個(gè)圖形場(chǎng)景(scene)連接在一個(gè)圖形窗口(view)上,圖形對(duì)象(graphics item)是被放在圖形場(chǎng)景(scene)上的。這里有一個(gè)簡(jiǎn)單的例子,首先頭文件定義了圖形窗口(view)與圖形場(chǎng)景(scene)。
class CustomWidgetV2 : public QWidget
{
Q_OBJECT
public:
explicit CustomWidgetV2(QWidget *parent = 0);
private:
QGraphicsView *m_view;
QGraphicsScene *m_scene;
};
在實(shí)現(xiàn)中首先將圖形場(chǎng)景(scene)與圖形窗口(view)連接。圖形窗口(view)是一個(gè)窗口部件,能夠被我們的窗口部件容器包含。最后我們添加一個(gè)小的矩形框在圖形場(chǎng)景(scene)中。然后它會(huì)被渲染到我們的圖形窗口(view)上。
#include "customwidgetv2.h"
CustomWidget::CustomWidget(QWidget *parent) :
QWidget(parent)
{
m_view = new QGraphicsView(this);
m_scene = new QGraphicsScene(this);
m_view->setScene(m_scene);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->addWidget(m_view);
setLayout(layout);
QGraphicsItem* rect1 = m_scene->addRect(0,0, 40, 40, Qt::NoPen, QColor("#FFBB33"));
rect1->setFlags(QGraphicsItem::ItemIsFocusable|QGraphicsItem::ItemIsMovable);
}
2.3.3. 數(shù)據(jù)適配
到目前為止,我們主要涵蓋基本數(shù)據(jù)類型以及如何使用視圖部件和圖形視圖。通常在我們的應(yīng)用程序中,我們將需要更大量的結(jié)構(gòu)化數(shù)據(jù),也必須持續(xù)存儲(chǔ)。數(shù)據(jù)也需要顯示。對(duì)于這個(gè) Qt 使用的模型。一個(gè)簡(jiǎn)單的模型是字符串列表模型,它被字符串填充,然后附加到列表視圖。
m_view = new QListView(this);
m_model = new QStringListModel(this);
view->setModel(m_model);
QList<QString> cities;
cities << "Munich" << "Paris" << "London";
model->setStringList(cities);
另一個(gè)比較普遍的用法是使用 SQL(結(jié)構(gòu)化數(shù)據(jù)查詢語(yǔ)言)來(lái)存儲(chǔ)和讀取數(shù)據(jù)。Qt 自身附帶了內(nèi)嵌版的 SQLLite 并且也支持其它的數(shù)據(jù)引擎(比如 MySQL,PostgresSQL,等等)。首先你需要使用一個(gè)模式來(lái)創(chuàng)建你的數(shù)據(jù)庫(kù),比如像這樣:
CREATE TABLE city (name TEXT, country TEXT);
INSERT INTO city value ("Munich", "Germany");
INSERT INTO city value ("Paris", "France");
INSERT INTO city value ("London", "United Kingdom");
為了能夠在使用 sql,我們需要在我們的項(xiàng)目文件(*.pro)中加入 sql 模塊。
QT += sql
然后我們可以使用 C++ 打開(kāi)我們的數(shù)據(jù)庫(kù)。首先,我們需要檢索指定數(shù)據(jù)庫(kù)引擎的新數(shù)據(jù)庫(kù)對(duì)象。使用此數(shù)據(jù)庫(kù)對(duì)象,我們打開(kāi)數(shù)據(jù)庫(kù)。對(duì)于 SQLite 這樣的數(shù)據(jù)庫(kù)我們可以指定一個(gè)數(shù)據(jù)庫(kù)文件的路徑。Qt提供了一些高級(jí)的數(shù)據(jù)庫(kù)模型,其中有一種表格模型(table model)使用表格標(biāo)示符和一個(gè)選項(xiàng)分支語(yǔ)句(where clause)來(lái)選擇數(shù)據(jù)。這個(gè)模型的結(jié)果能夠與一個(gè)鏈表視圖連接,就像之前連接其它數(shù)據(jù)模型一樣。
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName('cities.db');
if(!db.open()) {
qFatal("unable to open database");
}
m_model = QSqlTableModel(this);
m_model->setTable("city");
m_model->setHeaderData(0, Qt::Horizontal, "City");
m_model->setHeaderData(1, Qt::Horizontal, "Country");
view->setModel(m_model);
m_model->select();
對(duì)于更高級(jí)別的模型操作,Qt 提供了一個(gè)排序文件代理模型,允許我們使用基礎(chǔ)的分類排序和數(shù)據(jù)過(guò)濾來(lái)操作其它的模型。
QSortFilterProxyModel* proxy = new QSortFilterProxyModel(this);
proxy->setSourceModel(m_model);
view->setModel(proxy);
view->setSortingEnabled(true);
過(guò)濾是基于要過(guò)濾的列和一個(gè)字符串作為過(guò)濾器參數(shù)完成的。
proxy->setFilterKeyColumn(0);
proxy->setFilterCaseSensitive(Qt::CaseInsensitive);
proxy->setFilterFixedString(QString)
過(guò)濾器代理模型實(shí)際上比這里演示得更強(qiáng)大?,F(xiàn)在我們記住存在這樣一個(gè)強(qiáng)大的工具就足夠了。
提示
這里是綜述了我們可以在 Qt 5 中開(kāi)發(fā)的不同類型的經(jīng)典應(yīng)用程序。桌面應(yīng)用程序正在發(fā)生著改變,不久之后移動(dòng)設(shè)備將會(huì)占據(jù)我們的世界。移動(dòng)設(shè)備的用戶界面設(shè)計(jì)非常不同。它們相對(duì)于桌面應(yīng)用程序更加簡(jiǎn)潔,只需要專注的做一件事情。動(dòng)畫(huà)效果是一個(gè)非常重要的部分,用戶界面需要生動(dòng)活潑。傳統(tǒng)的 Qt 技術(shù)已經(jīng)不適于這些市場(chǎng)了。
2.3.4. Qt Quick 應(yīng)用
在現(xiàn)代的軟件開(kāi)發(fā)中有一個(gè)內(nèi)在的沖突,用戶界面的改變速度遠(yuǎn)遠(yuǎn)高于我們的后端服務(wù)。在傳統(tǒng)的技術(shù)中我們開(kāi)發(fā)的前端需要與后端保持相同的步調(diào)。當(dāng)一個(gè)項(xiàng)目在開(kāi)發(fā)時(shí)用戶想要改變用戶界面,或者在一個(gè)項(xiàng)目中開(kāi)發(fā)一個(gè)用戶界面的想法就會(huì)引發(fā)這個(gè)沖突。敏捷的項(xiàng)目需要敏捷的方法。
Qt Quick 提供了一個(gè)類似 HTML 聲明語(yǔ)言的環(huán)境應(yīng)用程序作為你的用戶界面前端(the front-end),在你的后端使用本地的 C++ 代碼。這使我們能夠獲得兩端的最佳的開(kāi)發(fā)效果。
下面是一個(gè)簡(jiǎn)單的 Qt Quick UI:
import QtQuick 2.5
Rectangle {
width: 240; height: 1230
Rectangle {
width: 40; height: 40
anchors.centerIn: parent
color: '#FFBB33'
}
}
這種聲明語(yǔ)言被稱作 QML,它需要運(yùn)行時(shí)才能執(zhí)行。Qt 提供了一個(gè)典型的叫做 qmlscene 的運(yùn)行環(huán)境,但是想要寫(xiě)一個(gè)自定義的運(yùn)行環(huán)境也不是很困難,為此,我們需要一個(gè) quick view 并且將 QML 文檔作為它的資源。剩下的事情就只是顯示用戶界面了。
QQuickView* view = new QQuickView();
QUrl source = QUrl::fromLocalFile("main.qml");
view->setSource(source);
view.show();
回到我們?cè)缜暗睦又小?在這個(gè)例子中,我們使用了一個(gè) C++ 城市模型。如果我們可以在我們聲明的 QML 代碼中使用這個(gè)模型,那就再好不過(guò)了。
為了實(shí)現(xiàn)這一點(diǎn),我們首先編寫(xiě)我們的前端,看看我們將如何使用城市模型。在這種情況下,前端需要一個(gè)名為 cityModel 的對(duì)象,我們可以在列表視圖中使用它。
import QtQuick 2.5
Rectangle {
width: 240; height: 120
ListView {
width: 180; height: 120
anchors.centerIn: parent
model: cityModel
delegate: Text { text: model.city }
}
}
為了啟用 cityModel,我們可以復(fù)用我們以前的模型,并將context屬性添加到我們的 root context 中(root context 是主文檔中的另一個(gè) root-element)。
m_model = QSqlTableModel(this);
... // some magic code
QHash<int, QByteArray> roles;
roles[Qt::UserRole+1] = "city";
roles[Qt::UserRole+2] = "country";
m_model->setRoleNames(roles);
view->rootContext()->setContextProperty("cityModel", m_model);
注意
這不是完全正確的用法,作為包含在 SQL 表格模型列中的數(shù)據(jù),一個(gè) QML 模型的任務(wù)是來(lái)表達(dá)這些數(shù)據(jù)。所以需要做一個(gè)在列和任務(wù)之間的映射關(guān)系。請(qǐng)查看 QML 和 QSqlTableModel 幫助文檔獲得更詳細(xì)的信息。
2.4. 總結(jié)
我們已經(jīng)看到如何安裝 Qt SDK 以及如何創(chuàng)建我們的第一個(gè)應(yīng)用程序。然后,我們介紹了不同的應(yīng)用程序類型,以概述 Qt,展示了 Qt 為應(yīng)用程序開(kāi)發(fā)提供的一些功能。希望這些能使大家對(duì) Qt 有一個(gè)初步的印象,Qt 是一個(gè)非常豐富的用戶界面工具包,并提供應(yīng)用程序開(kāi)發(fā)人員可以期待的一切。不過(guò),Qt 并不會(huì)將您鎖定到特定的庫(kù)中,因?yàn)槟梢噪S時(shí)使用其他庫(kù)或者擴(kuò)展 Qt。Qt 對(duì)于不同類型的應(yīng)用程序開(kāi)發(fā)支持非常豐富:包括控制臺(tái)程序,經(jīng)典的桌面用戶界面程序和觸屏用戶界面程序。
本文參考鏈接:Get Started