Qt訊號和槽機制&emit的使用
技術標籤:c++
1.相關概念:
[1].訊號(Signal)就是在特定情況下被髮射的事件
[2].槽(Slot)就是對訊號響應的函式。槽就是一個函式
[3].訊號與槽之間的關聯:是用 QObject::connect() 函式實現的,其基本格式是:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
//訊號發出者,處理的訊號, 訊號接收者,處理動作方法(槽函式)。
註解:
[1].sender 是發射訊號的物件的名稱,
[2].signal() 是訊號名稱。訊號可以看做是特殊的函式,需要帶括號,有引數時還需要指明引數。
[3].receiver 是接收訊號的物件名稱,slot() 是槽函式的名稱,需要帶括號,有引數時還需要指明引數。
[4].SIGNAL 和 SLOT 是 Qt 的巨集,用於指明訊號和槽,並將它們的引數轉換為相應的字串。
使用時需注意:
[1].一個訊號可以連線多個槽, 當一個訊號與多個槽函式關聯時,槽函式按照建立連線時的順序依次執行,例如:
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int));
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int));
[2]. 多個訊號可以連線同一個槽,
connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()))
[3]. 一個訊號可以連線另外一個訊號
[4]. 嚴格的情況下,訊號與槽的引數個數和型別需要一致,至少訊號的引數不能少於槽的引數。如果不匹配,會出現編譯錯誤或執行錯誤。
[5]. 在使用訊號與槽的類中,必須在類的定義中加入巨集 Q_OBJECT
[6]. 當一個訊號被髮射時,與其關聯的槽函式通常被立即執行,就像正常呼叫一個函式一樣。只有當訊號關聯的所有槽函式執行完畢後,才會執行發射訊號處後面的程式碼。
2.自定義槽
可當作槽函式的:任意的成員函式,普通全域性函式,靜態函式。
槽函式需要和訊號一致(引數列表,返回值)如果訊號沒有返回值,槽函式一定沒有返回值。
【舉例】:讓按鈕2點選一下,就能改變按鈕上的文字。
[1].首先,在.h檔案中宣告:
[2]在.cpp檔案對該函式進行定義:
[3]給按鈕聯結自定義的槽函式 mySlot:
connect(b2, &QPushButton::released, this, &MainWidget::mySlot);
[4].執行
3.自定義訊號
1.訊號必須有signals關鍵字來宣告
2.訊號沒有返回值,但可以有引數。
3.訊號就是函式的宣告,只需宣告,無需定義。
4.emit發射訊號
emit是Qt關鍵字,像其他關Qt擴充套件一樣,它也會被C++前處理器轉換成標準的C++程式碼。
使用:在A中對B使用訊號
主要步驟:訊號的建立,槽函式的建立,A類訊號和B類槽函式的聯接和使用
***A類的cpp***
void A::Dome()
{
B = new B;
******//在這裡要先將B類例項化***
***//訊號與槽需要例項化物件******
connect(this, SIGNAL(mySignal()), B, SLOT( BmySlot1()));
***//將A類的訊號和B類的槽函式連結起來***
emit void AmySignal();
***//發出訊號***
}
***B類的cpp***
void B::BmySlot1()
{
printf("hello world\n");
***//實現***
}
【舉例】
需求:有兩個視窗:主視窗和子視窗,讓主視窗的按鈕能跳轉到子視窗,子視窗的按鈕能跳轉到主視窗。
疑問點:從主視窗跳轉到子視窗,因為主視窗中有子視窗物件。但是要在子視窗中顯示主視窗,由於子視窗中沒有主視窗的物件。也不能有,否則進入死迴圈,邏輯錯誤。
[1].在main函式中把主視窗MainWidget加入程序
int main(int argc, char *argv[])
{
QApplication a(argc, argv); //建立一個QApplication類物件,有且只有一個應用程式物件!
MainWidget w1;
w1.show();
return a.exec();
}
[2].建立主視窗,在主視窗中建立一個按鈕,並connect到槽函式
setWindowTitle("老大"); //給視窗命名。
but3.setParent(this);
but3.setText("切換到子視窗");
but3.move(50,50);
connect(&but3, &QPushButton::released,this,&MainWidget::changeWin);
//在主視窗類中定義和宣告槽函式MainWidget::changeWin
public: void changeWin();
void MainWidget::changeWin(){
//子視窗顯示
w.show();
//本視窗隱藏
this->hide();
}
[3].建立子視窗,並讓子視窗加入到主視窗。
建立子視窗檔案widget.h/widget.cpp
在主視窗檔案中宣告子視窗
private: Widget w;
[4]在主視窗中處理子視窗訊號
// 先給子視窗新增自定義訊號:mySignal,並connect到主視窗的dealSub槽函式
connect(&w, &Widget::mySignal,this,&MainWidget::dealSub);
// mySignal():在子視窗中有申明訊號函式:但是沒有定義
signals:void mySignal(); //在子視窗中申明訊號函式
// dealSub():在主視窗中申明和定義槽函式
public :void dealSub();//申明:
//在相關.cpp檔案中定義
void MainWidget::dealSub(){
w.hide();//子視窗隱藏
show(); //本視窗顯示
}
[5].在子視窗中新增按鈕,並讓其實現跳轉到主視窗
1).在子視窗檔案中新增按鈕
b3.setParent(this); //通過setParent指定父級
b3.setText("返回上一級視窗");
b3.resize(200, 40);//設定按鈕的大小
b3.move(200, 200);//以Qwidget左上角為(0, 0),移動按鈕
2).給按鈕訊號connect子視窗的sendSlot槽函式。
connect(&b3, &QPushButton::clicked,this,&Widget::sendSlot);
3).在子視窗類中宣告和定義槽函式
public:void sendSlot();
4).定義槽函式:
void Widget::sendSlot(){
emit mySignal(); //觸發子視窗的mySignal()訊號。
}
mySinal()函式子視窗中有申明,但沒有一個具體實現,這是為何?
答案請看《自定義訊號的定義規則第3條》