一個稍微複雜的Qt程式

2020-07-16 10:04:47
《第一個Qt程式》中使用 MainWindow 作為主介面,內建一個 QLabel 控制元件,所有程式碼都寫在 main() 函數內部。本節我們將主要程式碼封裝到一個類的內部,然後在 main() 函數中建立該類的物件,這貌似更加符合 C++ 規範。

編寫程式碼

我們在 D:QtDemo 資料夾建立三個程式碼檔案,分別是 MyMainWindow.h、MyMainWindow.cpp 和 main.cpp,各個檔案的具體程式碼如下所示。

1) MyMainWindow.h 檔案程式碼:
#ifndef MYMAINWINDOW_H
#define MYMAINWINDOW_H

#include <QtWidgets/QMainWindow>
#include <QtWidgets/QLabel>

class MyMainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MyMainWindow();
    ~MyMainWindow();
private:
    QLabel *m_pLabel;
};

#endif
MYMAINWINDOW_H 可以防止標頭檔案被重複包含,不了解的讀者請猛擊《防止C語言標頭檔案被重複包含》。

Q_OBJECT 是一個宏,這種寫法對初學者來說是非常陌生的,它是 Qt 自己的語法擴充套件。Qt 的這種做法像極了早期的 C++:
  • C++ 在C語言的基礎上發展而來,C++ 擴充套件了C語言的語法,早期的 C++ 程式碼都是先被轉換為C語言程式碼,再使用C語言編譯器編譯。
  • Qt 是基於 C++ 的,但是它對 C++ 的語法進行了擴充套件(比如信號和槽機制、內省機制等),並增加了一些關鍵字(例如 signals、slots、emit 等),在真正編譯之前,擴充套件語法先被轉換成 C++ 程式碼(通過 moc 工具),然後再使用 C++ 編譯器編譯。

Qt 想要的功能 C++ 沒有,怎麼辦?那就自己上,親自實現這個功能!為了支援這些擴充套件功能,Qt 甚至實現了一個微型編譯器——元物件編譯器(Meta-Object Compiler, moc)。

C++ 為了保持程式執行的高效性,僅通過 RTTI(Run-Time Type Information,執行時型別識別)提供了非常簡陋的內省機制,幾乎沒有用武之地。Qt 拋棄了 C++ 自帶的內省機制,另起爐灶,創造了更加強大的元物件(meta object)系統,以此來支援完整的內省機制。

Q_OBJECT 宏就宣告了 Qt 元物件系統必須的函數和成員變數,之後我們會用 moc 工具生成元物件系統的實體函數程式碼。繼承 Qt 類時建議在類宣告的開頭新增 Q_OBJECT 宏,否則有時會出現莫名其妙的錯誤;如果你使用了信號和槽機制,Q_OBJECT 宏就是必須新增的,因為信號和槽依賴於元物件系統。

2) MyMainWindow.cpp 檔案程式碼:
#include "MyMainWindow.h"

MyMainWindow::MyMainWindow(): QMainWindow(){
    this -> setWindowTitle("MyMainWindow演示");  //設定標題
    this -> resize(360, 140);  //設定客戶區大小

    m_pLabel = new QLabel("C語言中文網", this);
    m_pLabel -> setGeometry(130, 50, 160, 30);  //設定Label控制元件的幾何尺寸
}

MyMainWindow::~MyMainWindow(){
    delete m_pLabel;
    m_pLabel = NULL;
}
該原始檔裡只有一個建構函式和一個解構函式。注意解構函式,它刪除之前 new 的標籤控制元件物件,並把指標設定為 NULL。

3) main.cpp 檔案程式碼:
#include <QtWidgets/QApplication>
#include "MyMainWindow.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MyMainWindow w;
    w.show();

    return app.exec();
}
main 函數還是一如既往的簡單,由於使用自定義的 MyMainWindow 作為主視窗類,所以是包含了 MyMainWindow.h 和 QApplication 兩個標頭檔案。

編譯程式碼

需要手工編寫的程式碼就這些,接下來的任務就是如何編譯生成可執行程式了。

前面提到 Qt 元物件系統,Qt 是基於 C++ 開發的,而 C++ 本身並沒有元物件系統。元物件系統是 Qt 專門為 C++ 做的擴充套件功能,用於支援非常強大的信號/槽機制、內省機制等,後面我們會詳細講解,本節我們重點學習 moc 工具的使用。下面逐步介紹編譯連結本節程式的過程。

1) 進入資料夾

開啟 Qt 命令列工具,進入程式碼所在資料夾:

cd /d D:QtDemo

2) 使用 moc 工具

使用 moc 工具生成 MyMainWindow 類的元物件系統程式碼檔案 moc_MyMainWindow.cpp :

moc MyMainWindow.h -o moc_MyMainWindow.cpp

moc 工具會搜尋標頭檔案 MyMainWindow.h 裡面所有的 Q_OBJECT 宏,並生成相應的元物件系統實際原始碼,輸出儲存為 moc_MyMainWindow.cpp 檔案。

3) 編譯和連結 .cpp 檔案

加上剛才手動編寫的 MyMainWindow.cpp 和 main.cpp,我們總共要編譯三個 C++ 原始碼檔案:

g++  moc_MyMainWindow.cpp MyMainWindow.cpp main.cpp  -std=c++0x  -I"D:Qt5.9mingw53_32include"  -L"D:Qt5.9mingw53_32lib"  -lQt5Core -lQt5Gui -lQt5Widgets  -o main

4) 執行 main.exe

生成 main.exe 之後,在 Qt 命令列工具裡輸入main.exe命令就可以執行該程式,看到顯示的效果。

生成main.exe的整個流程
生成 main.exe 的整個流程