信號和槽機制是Qt的核心機制,可以讓編程人員將互不相關的對象綁定在一起,實現對象之間的通信。
聲明了信號的對象,當其狀態改變時,信號就由該對象發送出去,而且該對象只負責發送信號,它不知道另一端是誰在接收這個信號。
槽用于接收和處理信號,一個槽并不知道是否有任何信號與自己相連接。
槽實際上只是普通的對象成員函數。當一個信號被發射時,與其相關的槽將被立即執行,就像一個正常的函數調用一樣。
信號與槽機制完全獨立于任何GUI事件循環。
信號
①信號(signal)的聲明是在一個類的頭文件中進行的
②Qt的signal關鍵字指出進入了信號聲明區,隨后即可聲明自己的信號
例如:
signals:void stateChanged(int nNewVal); //定義信號
這里signals是Qt的關鍵字,而非C++的關鍵字。
信號函數stateChanged定義了信號stateChanged,這個信號帶有參數nNewVal
信號函數語法受到以下幾點約束:
①函數返回值是void類型,因為觸發信號函數的目的是執行與其綁定的槽函數,無須信號函數返回任何值。
②開發人員只能聲明而不能實現信號函數。
③信號函數被moc自動設置為protected,因而只有包含一個信號函數的那個類及其派生類才能使用該信號函數。
④信號函數的參數個數、類型由開發人員自行設定。這些參數的職責是封裝類的狀態信息,并將這些信息傳遞給槽函數。
⑤只有QObject及其派生類才可以聲明信號函數
槽
①槽函數和普通的C++成員函數一樣,可以被正常調用。
②槽唯一的特殊性就是很多信息可以與其相關聯。
③當與其關聯的信號被發送時,這個槽就會被調用。
④槽可以有參數,但槽的參數不能有默認值。關鍵字slots表名進入了槽函數聲明區。
槽的聲明也是在頭文件中進行的,例如:
public slots: //此語句說明后面就是槽函數void Function(int nNewVal){qDebug() << "new Values" << nNewVal; //顯示變量 }
槽函數的返回值是void類型,因為信號和槽機制是單向的:信號被發送后,與其綁定的槽函數會被執行,但不要求槽函數返回任何執行結果。和信號函數一樣,只有QObject及其派生類才可以定義槽函數。
既然槽函數是普通的成員函數,因此與其他的函數一樣,它們也有存取權限(public,protected,private)。也就是說,人們能控制其他類能夠以怎樣的方式調用一個函數。
關聯信號與槽
通過調用QObject::connect函數可以綁定一個信號函數和一個槽函數,該函數最常用的格式如下:
connect(sender,SIGNAL(signal_func()),receiver,SLOT(slot_func()))
其中sender及receiver都是指向QObject(或其子類)對象的指針
前者指向發送信號的對象,后者指向處理信號的對象,兩者分別被稱為“發送者”及“接收者”。
signal_func以及slot_func分別是這兩個對象中定義的信號函數和槽函數。
當指定信號signal時一般使用Qt的宏SIGNAL,指定槽函數時必須使用宏SLOT。
一個信號函數可以和多個槽函數綁定。
多個信號函數可以和一個槽函數綁定。
使用信號和槽機制時應該注意以下幾點:
①信號和槽機制與普通函數調用一樣,如果使用不當,在程序執行時也有可能產生死循環
②如果一個信號與多個槽相聯系,那么當這個信號被發送時,與之相關的槽被激活的順序將是隨機的
③宏定義不能用在信號和槽的參數中。
④信號和槽的參數個數與類型必須一致
信號和槽舉例
?
再次建立頭文件
exampleA.h,修改其內容為
#ifndef EXAMPLEA_H
#define EXAMPLEA_H
#include<QCoreApplication>
class CExampleA:public QObject
{Q_OBJECTint m_Value;// 定義私有成員
public:CExampleA(){m_Value = 0;}void SetValue(int nNewVal){if (m_Value == nNewVal){ return ; }m_Value = nNewVal;// emit函數用來激活信號函數,發送信號emit stateChanged(m_Value);}
signals: // 定義信號函數,帶參數void stateChanged(int nNewVal);
};
#endif // EXAMPLEA_H
?exampleB.h,修改其內容為
#ifndef EXAMPLEB_H
#define EXAMPLEB_H
#include<QDebug> //包含調式類
#include<QCoreApplication>
class CExampleB:public QObject
{Q_OBJECT
public:CExampleB(){}
public slots: //定義槽函數void Function(int nNewVal) //nNewVal為100{qDebug() << "new Values" << nNewVal;}
};#endif // EXAMPLEB_H
?再次打開新建對話框,添加主函數文件
?
main.cpp中修改為
?
#include<exampleA.h>
#include<exampleB.h>
int main()
{CExampleA a; //創建CExampleA類的對象a,調用構造函數,m_Value = 0CExampleB b; //創建CExampleB類的對象b//連接信號和槽,connect函數要求發送對象和接收對象均為指針,a,b是對象名,&a,&b是發送對象的指針和接收對象的指針。QObject::connect(&a,SIGNAL(stateChanged(int)),&b,SLOT(Function(int)));a.SetValue(100); //調用a對象的公有函數return 0;
}
運行
簡單實現了信號與槽的功能