1. 程式人生 > 其它 >Qt訊號和槽機制&emit的使用

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條》