一.信號和槽概念
1. 信號(Signal)
概念:
信號是 Qt 對象在狀態發生變化或事件發生時自動發出的通知。
比如按鈕被點擊、文本框內容變化、定時器超時等,都會發出相應信號。本質:
它只是一個函數聲明(沒有函數體),由 Qt 的
moc
工具生成底層實現。發出信號時,不關心有沒有槽接收,也不關心槽的實現細節。
信號可以攜帶參數,將數據一并傳遞給槽。
信號本質就是函數,可以分為兩類。
1.內置信號,就是系統提供的信號,Qt 各種控件已經在類內部聲明并實現的信號eg.&QPushButton::clicked? 直接使用就可以。
2.自定義信號,只需要在.h文件中進行聲明就可以,不需要定義實現。
如何才能觸發出自定義的信號呢?
emit?valueChanged(); 當然不寫emit也行,不過最好還是寫上表示發送自定義信號。
2. 槽(Slot)
概念:
槽是一個可以被信號調用的普通成員函數,用于處理信號傳遞過來的事件或數據。本質:
槽函數和普通成員函數沒有區別,只是通過
connect()
機制與信號關聯后,會在信號觸發時被自動調用。槽函數可以有參數,也可以沒有,參數類型和順序需要與信號保持一致(或是信號的參數可以轉換為槽的參數類型)。
槽就相當于一個回調函數,發送了某個信號調用對于應的槽函數進行處理。
槽函數需要在.h文件中聲明,并在.cpp文件中實現定義(處理信號的邏輯)
信號和槽的參數關系
信號和槽函數都可以有參數。信號和對應連接的槽函數有規則
1.信號函數的參數數量<=槽函數的參數槽函數可以少接收一些參數,但不能多于信號提供的參數。多出來的信號參數會被自動丟棄
2.信號函數的參數能和慘函數參數類型相同或者能隱式類型轉換
二.connect()函數
那怎么把信號和槽關聯起來呢?
connect() 用于建立信號和槽之間的連接,讓某個信號觸發時自動調用對應的槽函數。
static QMetaObject::Connection connect(const QObject *sender,const char *signal,const QObject *receiver,const char *method,Qt::ConnectionType type = Qt::AutoConnection );
sender:信號發出者
signal:信號(函數指針或 SIGNAL 宏)
receiver:槽接收者
slot:槽(函數指針或 SLOT 宏)
type:連接類型(
Qt::AutoConnection
默認)eg.
connect(myButton,&QPushButton::clicked,this,&My_MainWindow::myhandle);1.myButton? 信號從哪一個控件發出的
2.&QPushButton::clicked? 哪一個信號函數
3.this(當前窗口對象)? 誰接收信號
4.&My_MainWindow::myhandle? 對應關聯的槽函數
三.信號和槽基本用法
1. 創建一個控件(信號的發起者)
有兩種方式:
? ? ? ? 1.代碼創建
這種方式創建的是局部變量(作用域在構造函數里)。
也可以在 .h 頭文件里提前聲明為成員變量,這樣生命周期和類對象一致
? ? ? ? 2.圖形化界面創建
在 .ui 文件中直接拖拽控件到窗體上,保存后編譯會自動生成對應的對象(在 ui_*.h 里)
2. 信號
信號有兩種來源:
內置信號:Qt 控件自帶的,比如
QPushButton::clicked()
。自定義信號:
在類的
signals:
區域聲明(不需要實現),使用
emit
發射。3.聲明并定義槽函數
1.代碼生成的,手動.h聲明 .cpp定義槽函數
2.如果是通過圖形化界面生成的控件就可以對控件 右鍵 選擇信號名稱,?????
Qt 會自動在
.h
里聲明并在.cpp
里定義槽函數。
4. 連接(connect)信號和槽
1.通過代碼生成的控件需要手動連接
2.通過圖形化界面生成的控件自動連接 不需要顯示連接
注意:如果自己再手動連接一次,就會變成重復連接,導致一次信號觸發兩次槽函數
5. 斷開連接(disconnect)
必須用與連接時相同的方式來斷開:
如果是函數指針連接,就用函數指針斷開:
如果是宏方式連接(UI 自動生成的槽),需要用宏方式斷開。
如果要斷開所有槽,可以把槽參數設為
nullptr
:disconnect(ui->pushButton, nullptr, this, nullptr);
這兩個nullptr分別代表,所有的信號對所有的槽函數都進行斷開
使用 Lambda 表達式定義槽函數
在 Qt 中,槽函數不僅可以是類成員函數,還可以直接使用 lambda 表達式。
Lambda 表達式的本質是一個匿名函數,特別適合一次性使用的回調場景,比如臨時響應某個信號,不想單獨寫一個成員函數時。