Qt 是一個C++ GUI應用框架,Qt 具有良好的可移植性支持大多數桌面和移動操作系統並常用於嵌入式開發。
Qt的發行版分為商業版和開源版,提供了Qt Creator作為輕量級IDE。
Hello World!
Qt應用的UI界面設計支持xml或者Qt Designer進行可視化設計,也可以通過C++代碼建立視圖。
Qt中的大多數類繼承自QObject(沒有繼承QObject的類在開發中造成了很大麻煩),QtGui編程中各種可視化組件均繼承自QWidget。
每個Qt GUI應用有且只有一個頂級組件,它可以是QWidget ,QMainWindow窗口應用,QDialog (對話框)。
上述 Qt 工程包括:
-
.pro 文件 qmake配置文件
-
dialog.h頭文件 聲明界面方法等
-
diaglog.cpp 事件監聽及相應代碼
-
main.cpp 入口和主程序邏輯
除了使用Qt Designer或編輯.ui文件外,Qt可以使用C++代碼控制ui組件。這里我們完全使用代碼創建一個與效果相同的工程,並解釋它的機制。
mainwindow. h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
//防止重復包含的哨兵,C/C++慣用
#include <QMainWindow>
//包含組件
namespace Ui { //定義namespace
class MainWindow;
}
//頂級組件MainWindow的類聲明
class MainWindow : public QMainWindow
{
Q_OBJECT
//Q_OBJECT宏提供了信號槽機制、國際化機制和不基於C++ RTTI的反射能力
//建議均包含此宏
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
//構造函數與析構函數
private:
Ui::MainWindow *ui; //定義了ui作為訪問接口
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
包含mainwindow類的實現以及事件的響應代碼(當然這里沒有...)
注意構造函數使用了初始化列表(這種縮進容易讓人暈掉...)
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <QLabel>
#include <QPushButton>
//頭文件包含
int main(int argc, char *argv[]) //main函數
{
QApplication a(argc, argv);//定義應用對象,從參數看它是支持命令行的
MainWindow w; //定義mainwindow頂級組件
QLabel *label = new QLabel("Hello World!", &w); //自定義Label組件
QPushButton *button = new QPushButton("Disp", &w);//自定義PushButton組件
w.show(); //繪制主窗口w
button -> show(); //繪制按鈕
QObject::connect(button,SIGNAL(clicked()),label,SLOT(show()));
/*重點來了:信號槽
* 信號槽是Qt實現事件響應的機制,當某一組件的某事件發生時將會發出相應的信號(SIGNAL)
* 與此信號相關的槽(SLOT)將會收到該信號並響應事件
*
* connect函數則可以將信號和槽關聯起來
* QObject::connect(Object *sender,Func signal,Object* reciver,Func slot)
* 信號和槽本質上都是函數,信號由組件定義,槽則由程序員定義
*/
return a.exec();
/* 運行消息循環
* 應用等待事件的發生並進行響應
*/
}
組件與布局
布局管理
與很多GUI框架一樣,Qt 提供了布局(layout) 作為空間的容器 以自動地管理組件的位置。
Qt Desinger可以方便地設置布局,Qt 同樣允許以C++代碼創建布局:
示例1:
#include <QApplication>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *w = new QWidget;
QLabel *label = new QLabel("Hello World!");
QPushButton *button = new QPushButton("Clear");
QHBoxLayout *layout = new QHBoxLayout;
layout ->addWidget(label);
layout ->addWidget(button);
w->setLayout(layout);
w->show();
QObject::connect(button,SIGNAL(clicked()),label,SLOT(clear()));
return a.exec();
}
示例2:
#include <QApplication>
#include <QWidget>
#include <QSpinBox>
#include <QSlider>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *window = new QWidget;
window->setWindowTitle("Enter your age");
QSpinBox *spinBox = new QSpinBox;
QSlider *slider = new QSlider(Qt::Horizontal);
spinBox->setRange(0, 130);
slider->setRange(0, 130);
QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)));
QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
spinBox->setValue(35);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(spinBox);
layout->addWidget(slider);
window->setLayout(layout);
window->show();
return app.exec();
}
以Qwidget或QDialog為頂級組件的應用可以使用上述代碼創建布局,以QMainWindow為頂級組件的應用無法用這種方式來創建布局。
其它常用組件請參考Qt API文檔...
組件介紹
QTimer 計時器
QTimer *timer = new QTimer(QObject *);
它可以使用start(int msec)方法來開始計時timer->start(1000);
start()函數同時還是一個槽函數。
當計時結束,timer組件將發出timeout()信號,然后開始下一輪計時。
timer -> stop();
方法將阻止繼續計時。
static void QTimer::singleShot(int msec, QObject receiver, SLOT());
該方法只會在第一次時間到后定向發出timeout()信號,不再繼續計時。這是一個靜態方法無需建立QTimer對象即可使用。
若QTimer的計時時間設為0,則當事件隊列為空時發出timeout()信號。
請不要這一機制而使用多線程機制代替。
當然,QWidget子類的timerEvent()方法可以更方便的實現計時。
QWidget::startTimer(interval)
實例方法用來啟動計時器,每隔interval毫秒發出執行一次QWidget::timerEvent(event)
方法。
菜單(QMenuBar)、工具(QToolBar)與狀態欄(QStatusBar)
示例:
#include "mainwindow.h"
#include <QApplication>
#include <QMenu>
#include <QMenuBar>
#include <QToolBar>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow *w = new MainWindow;
QAction *openAction = new QAction(w);
openAction ->setIconText("Open");//設置QACtion組件顯示的文字
openAction -> setStatusTip("Open a File");
//設置狀態欄信息,當鼠標指針指向該組件時信息會一直顯示
QMenu *fileMenu = w->menuBar()->addMenu("File");//新鍵菜單
fileMenu -> addAction(openAction); //新鍵菜單項
QToolBar *toolBar = w->addToolBar("F");//新建工具欄
toolBar->addAction(openAction);//添加工具
//QStatusBar *status = w -> statusBar();
//與QMenuBar類似的函數可以獲得狀態欄指針
w -> show();
return a.exec();
}
標准對話框
Qt 提供了消息、打開文件、保存文件、選擇顏色等標准對話框,它們可以實例化也可以通過靜態函數進行調用。
- QMessageBox 消息框
- QFileDialog 文件對話框(獲取路徑而已)
- QColorDialog 顏色對話框
- QInputDialog 輸入框
- QPrintDialog 打印對話框
下面以QMessageBox為例說明:
通過靜態函數使用對話框:
void QMessageBox::about(QWidget * parent, const QString & title, const QString & text)
顯示關於對話框,其標題是 title、內容是 text、父窗口是 parent,對話框只有一個 OK 按鈕。
void QMessageBox::aboutQt(QWidget * parent, const QString & title = QString())
顯示關於 Qt 對話框。
StandardButton QMessageBox::critical(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton)
顯示嚴重錯誤對話框。這個對話框將顯示一個紅色的錯誤符號。我們可以通過 buttons 參數指明其顯示的按鈕。默認情況下只有一個 Ok 按鈕,我們可以使用StandardButtons類型指定多種按鈕。
StandardButton QMessageBox::information(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton)
QMessageBox::information()函數與QMessageBox::critical()類似,不同之處在於這個對話框提供一個普通信息圖標。
StandardButton QMessageBox::question(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = StandardButtons( Yes | No ), StandardButton defaultButton = NoButton)
QMessageBox::question()函數與QMessageBox::critical()類似,不同之處在於這個對話框提供一個問號圖標,並且其顯示的按鈕是“是”和“否”兩個。
StandardButton QMessageBox::warning(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton)
QMessageBox::warning()函數與QMessageBox::critical()類似,不同之處在於這個對話框提供一個黃色嘆號圖標。
通過通過QMessageBox對象使用對話框
QMessageBox msg;
msg.setText("Hello");
msg.exec();
從示例可以看出QMessageBox需要事件循環,exec()同時也是QMessageBox()的槽函數。
更多精彩盡在API 文檔...
取代標准C++的做法
QString
Qt定義了QString類作為字符串以取代C++定義的兩種風格的字符串。
QString重載了"+"和"+="運算符進行字符串連接,Qt Creator也把字符串字面值當作QString來處理。
QString的sprintf()函數提供了類似C中printf()函數的作用,配合arg()函數使用以提供類型安全,不過作為GUI框架的QT這種用法較少。
對於原生C++的兩種字符串+,+=運算符可以將其轉換為QString並將其連接。 * QString的toStdString()實例方法和fromStdString()靜態方法可將QString和std::String相互轉換 *
QString::number()系列重載靜態函數可以將數字轉換為字符串或者使用str.setNum()完成同樣轉換。
因為QString::number()函數含有base參數所以可以用作進制轉換。
tr.toInt(bool *)
,str.toDouble(bool*)
接收一個bool指針作為參數,若轉換成功則返回結果並將參數設為true;否則參數則設為false。
str.mid()
,str.left()
,str,right()
函數提供截取子串功能。
str.indexof(QString sub,int from)
則可以返回子串的位置。
replace()和insert()函數提供代換和插入功能。
trimmed()函數可以去掉字符串首尾的空白字符(空格,[Tab],換行符)。
simplified()函數將連續的空白字符用一個空格代替。
toUpper()和toLower()則進行大小寫轉換。
QByteArray
QByteArray是一個二進制數組,以字節為單位, 常用作緩沖區。
QByteArray保證結尾一定是'\0'(其內部也可存儲 \0)這一特性保證它可以轉換char *(建議還是用QString)。
QByteArray提供了與QString相似的API。
QVariant
它是一個包含絕大多數Qt類、C++類、C++基本類型的共用體, 可以與任意的Qt類進行轉化,常用於泛型。
它被用於構建Meta - Object , 是QCore的一部分。
Qt線性容器
QVector
type必須提供默認構造函數,復制構造函數和賦值運算符。
發布Qt應用
發布Qt 編寫的軟件需要以"release" 配置編譯源代碼,Qt Creator左下角的運行工具欄中可以更改配置,Vs在[project/項目]->[屬性/properties]中進行配置。
將編譯得到的二進制可執行文件與必要的支持庫打包。
支持庫由.pro文件中設置的模塊決定,一般包含core和gui模塊的Qt應用需要以下支持庫文件:
-
Qt庫文件[Qt\lib]
-
Qt5Core.dll
-
Qt5Gui.dll
-
Qt5Widgets.dll
-
-
Qt Platform插件[Qt\plugins\platforms]
復制文件夾並刪除其中的.pdb文件,只保留.dll文件。
qwindows.dll】同名.dll文件中刪除帶有d后綴(debug模式所需)的.dll文件,如刪除"qwindowsd.dll",保留"qwindows.dll"。
Desktop平台下所需的文件:
- qoffscreen.dll
- qminimal.dll
- ICU庫[Qt\bin]
ICU庫用於提供對Unicode字符編碼的支持
- icudt53.dll
- icuin53.dll
- icuuc53.dll
-
C++ Runtime Library
-
msvcp120.dll
-
msvcr120.dll
-
-
OpenGl支持庫
- libEGL.dll
-
Windows平台相關
-
gpsvc.dll
-
kernel32.dll
-
其它技術
國 際化
Qt 使用Unicode編碼表示字符串為國際化創造了基礎,常用的有QTextCodec類以及QObject::tr()函數,后者是Qt推薦的做法。
tr函數是translation的簡寫,tr()函數是QObject類提供的靜態函數。
tr()函數接收一個字符串作為參數,並返回翻譯后的字符串。
其翻譯功能支持由Meta-Object等系統提供(后台硬系列)。
r函數的參數字符串中'&'的字符可以標記其后的一個字符,並將該字符設為快捷鍵。
在無法使用函數的場合(如數組的初始化列表),QT_TR_NOOP()和QT_TRANSLATE_NOOP()宏可以替代tr()函數,前者接收一個字符串作為參數並將其翻譯,后者可以處理多個字符串。
鑒於自動翻譯發展的現狀,國際化不是一個函數就能完成的,tr()函數是一個標記,國際化仍依賴人工翻譯。
(1) 在工程的.pro文件中增加【TRANSLATIONS += *.ts】
*代表ts文件具體文件名,ts文件是XML編碼的翻譯(源)文件
(2)創建.ts文件
使用lupdate命令,參數為工程的.pro文件
這命令是更新.ts文件,避免重復翻譯
(3) 使用Qt Linguist打開.ts文件,進行翻譯
Qt Linguist會提出翻譯建議,但是翻譯工作還要人工做
使用文件->發布命令在工程目錄下創建.qm文件
(4) 安裝.qm文件
包含頭文件【#include
QApplication a(argc, argv);
QTranslator trans;
trans.load("HelloWorld.qm");
a.installTranslator(&trans);
.qm文件為動態加載的,當更換語言后只需要更新.qm文件並重新運行程序即可,無需重新編譯。
Qt 多窗口程序設計
-
在項目上選擇添加新文件,Qt -> Qt 設計師模板類
-
選擇界面模板
-
選擇類名,注意不要和已有類重復。
Qt Creator會自動創建響應的頭文件(.h)、源文件(.cpp)和界面文件(.ui)
4)聲明新的界面類
在main.cpp文件中包含新的界面類頭文件
#include "mainwindow2.h"
在namespace Ui中添加新的界面類
namespace Ui {
class MainWindow;
class MainWindow2;
}
根據需要定義界面對象,在需要時調用其show()方法顯示界面。
Qt 應用圖標設置
運行圖標的設置
應用程序在Windows平台上運行時,任務欄中會出現圖標,一般窗口的左上角也會出現對應的圖標,將這個圖標稱為運行圖標。
運行圖標屬於整個應用,即QApplication對象,調用QApplication::setWindowIcon(QIcon(QString Path));
實例方法可以設置應用圖標。
文件圖標的設置
可執行文件也擁有自己的圖標,但這個圖標由操作系統設置。
windows平台下:
首先將圖標的ico文件放入工程目錄中,然后定義主文件名與工程同名的.rc文件(注意不是.qrc文件)。
在文件中寫入:IDI_ICON1 ICON DISCARDABLE"img.ico"
"img.ico"代表相對路徑和文件名)。保存文件並重新編譯就可以更新圖標。
圖標文件會以二進制格式寫入.exe文件中,制作發布版時無需包含.rc文件和圖標文件。