1. 程式人生 > >Qt 5中信號和槽的新語法

Qt 5中信號和槽的新語法

既然 自己的 edi val 接下來 很多 工具包 code 所有者

QT 是一個跨平臺的 C++ GUI 應用構架,它提供了豐富的窗口部件集,具有面向對象、易於擴展、真正的組件編程等特點,更為引人註目的是目前 Linux 上最為流行的 KDE 桌面環境就是建立在 QT 庫的基礎之上。QT 支持下列平臺:MS/WINDOWS-95、98、NT 和 2000;UNIX/X11-Linux、Sun Solaris、HP-UX、Digital Unix、IBM AIX、SGI IRIX;EMBEDDED- 支持 framebuffer 的 Linux 平臺。伴隨著 KDE 的快速發展和普及,QT 很可能成為 Linux 窗口平臺上進行軟件開發時的 GUI 首選。

概述

信號和槽機制是 QT 的核心機制,要精通 QT 編程就必須對信號和槽有所了解。信號和槽是一種高級接口,應用於對象之間的通信,它是 QT 的核心特性,也是 QT 區別於其它工具包的重要地方。信號和槽是 QT 自行定義的一種通信機制,它獨立於標準的 C/C++ 語言,因此要正確的處理信號和槽,必須借助一個稱為 moc(Meta Object Compiler)的 QT 工具,該工具是一個 C++ 預處理程序,它為高層次的事件處理自動生成所需要的附加代碼。

在我們所熟知的很多 GUI 工具包中,窗口小部件 (widget) 都有一個回調函數用於響應它們能觸發的每個動作,這個回調函數通常是一個指向某個函數的指針。但是,在 QT 中信號和槽取代了這些淩亂的函數指針,使得我們編寫這些通信程序更為簡潔明了。 信號和槽能攜帶任意數量和任意類型的參數,他們是類型完全安全的,不會像回調函數那樣產生 core dumps。

所有從 QObject 或其子類 ( 例如 Qwidget) 派生的類都能夠包含信號和槽。當對象改變其狀態時,信號就由該對象發射 (emit) 出去,這就是對象所要做的全部事情,它不知道另一端是誰在接收這個信號。這就是真正的信息封裝,它確保對象被當作一個真正的軟件組件來使用。槽用於接收信號,但它們是普通的對象成員函數。一個槽並不知道是否有任何信號與自己相連接。而且,對象並不了解具體的通信機制。

你可以將很多信號與單個的槽進行連接,也可以將單個的信號與很多的槽進行連接,甚至於將一個信號與另外一個信號相連接也是可能的,這時無論第一個信號什麽時候發射系統都將立刻發射第二個信號。總之,信號與槽構造了一個強大的部件編程機制。

信號

當某個信號對其客戶或所有者發生的內部狀態發生改變,信號被一個對象發射。只有 定義過這個信號的類及其派生類能夠發射這個信號。當一個信號被發射時,與其相關聯的槽將被立刻執行,就象一個正常的函數調用一樣。信號 - 槽機制完全獨立於任何 GUI 事件循環。只有當所有的槽返回以後發射函數(emit)才返回。 如果存在多個槽與某個信號相關聯,那麽,當這個信號被發射時,這些槽將會一個接一個地 執行,但是它們執行的順序將會是隨機的、不確定的,我們不能人為地指定哪個先執行、哪 個後執行。

信號的聲明是在頭文件中進行的,QT 的 signals 關鍵字指出進入了信號聲明區,隨後即可 聲明自己的信號。例如,下面定義了三個信號:

signals:

void mySignal(); void mySignal(int x); void mySignalParam(int x,int y);

在上面的定義中,signals 是 QT 的關鍵字,而非 C/C++ 的。接下來的一行 void mySignal() 定義了信號 mySignal,這個信號沒有攜帶參數;接下來的一行 void mySignal(int x) 定義 了重名信號 mySignal,但是它攜帶一個整形參數,這有點類似於 C++ 中的虛函數。從形式上 講信號的聲明與普通的 C++ 函數是一樣的,但是信號卻沒有函數體定義,另外,信號的返回 類型都是 void,不要指望能從信號返回什麽有用信息。

信號由 moc 自動產生,它們不應該在 .cpp 文件中實現。

槽是普通的 C++ 成員函數,可以被正常調用,它們唯一的特殊性就是很多信號可以與其相關聯。當與其關聯的信號被發射時,這個槽就會被調用。槽可以有參數,但槽的參數不能有缺省值。

既然槽是普通的成員函數,因此與其它的函數一樣,它們也有存取權限。槽的存取權限決定了誰能夠與其相關聯。同普通的 C++ 成員函數一樣,槽函數也分為三種類型,即 public slots、private slots 和 protected slots。

  • public slots:在這個區內聲明的槽意味著任何對象都可將信號與之相連接。這對於組件編程非常有用,你可以創建彼此互不了解的對象,將它們的信號與槽進行連接以便信息能夠正確的傳遞。
  • protected slots:在這個區內聲明的槽意味著當前類及其子類可以將信號與之相連接。這適用於那些槽,它們是類實現的一部分,但是其界面接口卻面向外部。
  • private slots:在這個區內聲明的槽意味著只有類自己可以將信號與之相連接。這適用於聯系非常緊密的類

槽也能夠聲明為虛函數,這也是非常有用的。

槽的聲明也是在頭文件中進行的。例如,下面聲明了三個槽:

public slots: void mySlot(); void mySlot(int x); void mySignalParam(int x,int y);

在即將到來的Qt 5中提供了一套新的語法。之前的語法依然可以使用,但是現在,我們有了全新的方式:

connect(sender, &Sender::valueChanged,
        receiver, &Receiver::updateValue);

C++11 Lambda表達式

至此之前,我們所有的示例都是基於C++98標準的。但是,如果你的編譯器支持C++11,我還是強烈建議你使用一些這個語言的新特性。現在,Lambda表達式至少被MSVC 2010GCC 4.5clang 3.1這幾個編譯器支持。不過對於後面兩個編譯器,你需要在編譯時加上-std=c++0x參數。

然後我們就可以這樣寫代碼了:

void MyWindow::saveDocumentAs() {
    QFileDialog *dlg = new QFileDialog();
    dlg->open();
    QObject::connect(dlg, &QDialog::finished, [=](int result) {
        if (result) {
            QFile file(dlg->selectedFiles().first());
            // ... 在這裏保存文檔 ...
        }
        dlg->deleteLater();
    });
}

這種語法允許我們更方便地編寫異步代碼。

Qt 5中信號和槽的新語法