第七章 探秘Qt的核心機制-信號與槽
注:要想使用Qt的核心機制信號與槽,就必須在類的私有數據區聲明Q_OBJECT宏,然后會有moc編譯器負責讀取這個宏進行代碼轉化,從而使Qt這個特有的機制得到使用。
所謂信號槽,簡單來說,就像是插銷一樣:一個插頭和一個插座。當某種事件發生之后,比如,點擊一下鼠標,或者按下某個按鍵,此時,這個組件就回發出一個信號。如果有一個槽,正好對應上這個信號,那么,這個槽函數就回被調用。
槽函數和普通的c++成員函數沒有很大的區別,它們也可以是virtual的;可以被重寫;可以使public、protected或者private的;可以被其他c++函數調用;參數可以是任何類型。槽函數可以和一個信號相連接,當這個信號發生時,它就被自動調用。
連接信號與槽是connect()函數,原型如下:
bool QObject::connect ( const QObject * sender, const QMetaMethod & signal, const QObject * receiver, const QMetaMethod & method, Qt::ConnectionType type = Qt::AutoConnection ) [static]
它可以把一個對象(sender)發送的信號(signal)和接收者(receiver)的槽函數(method)關聯起來,這樣當信號產生時與之關聯的槽函數就會被執行。在connect函數里面我們用到了Qt提供的兩個宏SIGNAL()和SLOT();這是Qt要求的,要關聯信號和槽必須借助於這兩個宏,兩個宏的定義如下:
#define SLOT(name) "1"#name
#define SIGNAL(name) "2"#name
通過這兩個宏,就可以把我們傳遞進去的槽和信號的名字轉化成字符串,並在這兩個字符串前面加上附加的字符。
如:
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(myslots()));
經過moc處理后就變成:
connect(ui->pushButton, "2clicked()", this, "1myslots()");
connect函數的最后一個參數type可以指定傳遞信號的方式,它是Qt::ConnectionType枚舉類型常量,常用連接類型如下表所列。
Constant | Value | Description |
Qt::AutoConnection | 0 | 當信號發送者和接收者處於同一線程內時,這個類型等同於DirectConnection,反之等同於QueuedConnection,這個類型也是connect函數的默認連接類型 |
Qt::DirectConnection | 1 | 信號一旦發射,與之關聯的槽函數立即執行 |
Qt::QueuedConnection | 2 | 當信號產生,信號會暫時被緩沖到一個消息隊列中,等待接收者的事件循環處理去隊列中獲取消息,然后執行和信號關聯的槽函數,這種方式既可以在同一線程內傳遞消息也可以跨線程操作 |
Qt::BlockingQueuedConnection | 4 | 這種類型類似於QueuedConnection,但是它只能應用於跨線程操作即發送者和接收者處於不同的線程中的情況,並且信號發送者線程會阻塞等待接收者的槽函數執行結束 |
Qt::AutoCompatConnection | 3 | 當兼容Qt3程序是的默認連接類型 |
一個信號可以和多個槽相連(槽會一個接一個地被調用,但是調用的順序是不確定的);
多個信號可以連接一個槽(只要任意一個信號產生,這個槽就回被調用);
一個信號可以連接到另一個信號;
槽可以被取消鏈接:
bool QObject::disconnect ( const QObject * sender, const QMetaMethod & signal, const QObject * receiver, const QMetaMethod & method ) [static]
這種情況並不經常出現,因為當一個對象delete之后,Qt自動取消所有連接到這個對象上面的槽。
要連接在一起的信號和槽,如果帶了參數,那么這些參數的順序和類型都要一致,並且信號帶的參數的個數可以多於槽,信號在發射的時候可以把參數傳遞給槽函數接收,這也是不同對象交互數據的一個方法,信號可以發送多個類型的數據給槽函數,但是槽函數不一定需要全部接收處理,這樣槽函數參數的個數可以少於或者等於信號參數的個數,但一定不能多於所連接信號的參數個數。為了正確的連接信號槽,信號和槽的參數類型以及出現的順序必須相同。
下面舉兩個例子,一個例子是使用connect函數連接信號槽,另個例子是使用Qt Creator的designer來設置信號槽(本質還是connect,只是圖形化)。
例子一:
1 #include <QAPPlication> 2 #include <QPushButton> 3 4 int main (int argc, char *argv[]) 5 { 6 QApplication app(argc, argv); 7 QPushButton *button = new QPushButton("Close"); 8 QObject::connect(button, SIGNAL(clicked()), button, SLOT(close())); 9 button->show(); 10 11 return app.exec(); 12 }
輸入以下指令編譯:
qmake -project
qmake
make
運行程序:
點擊按鈕“Close”,窗口會關閉。
例子二:
使用Qt Creator創建一個工程
如何讓界面在用戶單擊了“Close”按鈕后立刻消失,當然是connect一下clicked和close就搞定了。接下來看具體怎么做?雙擊signalslotdialog.ui進入designer
拖放一個Push Button到空間放置區,並修改text屬性為“Close”
單擊Qt Creator的“編輯(Edit)”菜單,在彈出的子菜單里面點選“編輯信號/槽(Edit signals/slots)”,此時,當鼠標移動到“Close”按鈕上時,按鈕顏色變了。然后單擊按鈕,拖動鼠標到對話框的空白處,會看到下圖所示界面
當松開鼠標左鍵,彈出“配置連接(Configure Connection)”對話框如圖所示
設置如下圖,單擊“確定”
這樣就connect了信號clicked和槽close
單擊編譯運行出現如下界面
單擊“Close”按鈕,界面就退出。