目錄
回顧C 語言信號
1、信號與槽
2、關聯信號與槽
2.1自動關聯信號與槽
2.2手動關聯信號與槽
2.3斷開信號與槽
3、自定義信號
3.1自定義信號使用條件
3.2自定義槽函數使用條件
4、信號與槽參數傳遞
4.1自定義一個帶參的信號
4.2關聯帶參的信號與槽
4.3發送一個帶參的信號
5、信號與槽的相互關聯
6、lambda表達式
?lambda 表達式的應用
?7、lambda 與 信號和槽
回顧C 語言信號
signal(設置信號處理方式)功能:注冊一個信號處理函數,當收到該信號后,就會觸發handler 函數表頭文件 #include<signal.h>定義函數 void *signal(int signum,void(* handler)(int));signum : 需要捕捉的信號。handler : 收到信號后執行的函數
1.捕捉的信號能自定義嗎? 不可以,只能使用系統預定義好的信號
2.信號可以傳輸數據嗎? 不可以,信號只負責通知
所以QT 在 C 語言的信號基礎進行封裝,把上述兩個問題都解決了。 在QT 中用戶可以自定義信號, 在QT 中用戶可以通過信號與槽傳遞參數。
信號:各種事件
槽: 響應信號的動作
1、信號與槽
當某個事件發生后,如某個按鈕被點擊了一下,它就會發出一個被點擊的信號(signal)。
某個對象接收到這個信號之后,就會做一些相關的處理動作(稱為槽slot)。
但是Qt對象不會無故收到某個信號,要想讓一個對象收到另一個對象發出的信號,這時候需要建立連接(connect)
//QT的四個信號
- pressed():鼠標按下時觸發。對應的函數是 mousePressEvent()。
- clicked():鼠標松開時觸發。如果鼠標拖拽到按鈕區域之外釋放則不會觸發。對應的函數是 mouseReleaseEvent()。一般情況下 connect 槽函數時使用該信號。
- released():鼠標松開時觸發。即使鼠標拖拽到按鈕區域之外釋放也會觸發。對應的函數是 mouseReleaseEvent()。
- toggled():設置 setCheckable(true) 后再單擊按鈕才會觸發該信號。一般用于多個按鈕組成 QButtonGroup 并且 setExclusive(true) 設置按鈕間互斥。 正常情況下單擊按鈕,響應順序為:pressed() — about 215ms — released() — almost 0ms — clicked()。
2、關聯信號與槽
關聯的方法有兩種:自動關聯,手動關聯。下面對此進行一次次介紹
2.1自動關聯信號與槽
在項目 增加信號和槽的方法一:在UI設計師中增加
第一步:右擊控件,在彈出的對話框,
在下拉列表中,選擇"轉到槽",會彈出選擇對話框
第二步:選擇自己信號
會自動生成槽函數(.h和.cpp)
第三步:當點擊相應的控件時,對應的槽函數就會被調用,從面是實現動態交互的效果
槽函數
2.2手動關聯信號與槽
QMetaObject::Connection QObject::connect(const QObject *sender,const char *signal,const QObject *receiver,const char *method,Qt::ConnectionType type = Qt::AutoConnection
);
其中,sender 表示信號發送者,signal 表示信號名,receiver 表示信號接收者,method 表示槽函數名,type 表示連接類型
type參數的值 | 描述 | 解釋 |
Qt::DirectConnection | 直接連接 | 即在信號發出時直接調用槽函數,槽函數會立即執行,而不管當前的線程是否與信號發出者在同一個線程 |
Qt::QueuedConnection | 排隊連接 | 將信號事件放入接收對象的事件隊列中,槽函數會在事件循環處理時被執行,適用于跨線程的連接 |
Qt::BlockingQueuedConnection | 阻塞排隊連接 | 槽函數會在接收對象的線程中執行,并且當前線程會阻塞,直到槽函數執行完成 |
Qt::AutoConnection | 自動連接 | 如果信號發送者和接收者在同一個線程,使用直接連接,否則使用排隊連接 |
Qt::UniqueConnection | 唯一連接 | 已經存在相同的連接,則不會創建新的連接,可以避免重復連接導致的問題,如重復執行槽函數等 |
?在QT4和QT5中,手動關聯有著意義重大的調整,QT4不會檢查信號與槽的參數是否匹配,而QT5會自動檢查信號與槽的參數是否匹配。
下面給出QT4和QT5的關聯例子:
QT4:
//手動關聯信號與槽 this 表示的是當前窗體,MainWindow
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(on_pushButton_clicked()));
QT5:
connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::show_msg);
2.3斷開信號與槽
語法:
語法: QT4: disconnect(信號發送者地址,SIGNAL(信號名(參數列表)),信號接收者地址,SLOT(槽名稱(參數列表)));
QT5: disconnect(信號發送者地址,&發送者類名::信號名,信號接收者地址,&接受者類名::槽名稱);
void MainWindow::on_pushButton_2_clicked()
{//取消信號與槽的關聯 QT4// disconnect(ui->pushButton,SIGNAL(clicked()),this,SLOT(on_pushButton_clicked()));//取消信號與槽的關聯 QT5disconnect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::on_pushButton_clicked);//因為自動關聯,QT軟件采用的是QT4的語法關聯,所以取消只能用QT4 。//關聯時使用了那種方法,取消時要一致!!qDebug() << "取消關聯";
}
注意:使用自動關聯的時候,QT軟件采用的是QT4的語法關聯,所以取消關聯只能用QT4;使用手動關聯的時候,關聯時使用了那種方法,取消時要一致
3、自定義信號
在QT中,信號是可以自定義的,語法如下:
//在xxx.h頭文件中 聲明信號
signals: void 信號名(參數列表);
注意:信號只需要聲明不需要定義!!!
?但是可以看到定義信號的時候可以參數,參數的類型在信號定義的時候必須已經確定,而且不能改變,信號默認只能傳遞基本的類型如下(列舉部分):
int:整數類型
double:雙精度浮點數類型
QString:字符串類型
QDate:日期類型
QTime:時間類型
QColor:顏色類型
在C++中,參數支持默認參數,那么在QT的信號定義時,當然也可以為參數設置默認值。
定義完自定義信號之后,需要代碼來控制發送信號,發送語法如下:
//使用 emit 信號名(參數列表); 發送信號
emit mysig(); //發送一個mysig信號
在發出信號時,如果沒有指定參數,則使用默認值。
自定義信號與槽的關聯和上面的關聯是類似的:
//信號在那個類中定義的,該類就是發送者connect(this,SIGNAL(mysig()),this,SLOT(getsig()));//發送信號emit mysig();//溫馨提示:信號的發送必須在"關聯后"發送,否則該信號失效
3.1自定義信號使用條件
- 聲明在類的signals域下
- 沒有返回值,void類型的函數
- 只有函數聲明,沒有定義
- 可以有參數,可以重載
- 通過emit關鍵字來觸發信號,形式:emit object->sig(參數);
3.2自定義槽函數使用條件
- qt4 必須聲明在 private/public/protected slots域下面,qt5之后可以聲明public下,同時還可以是靜態的成員函數,全局函數,lambda表達式
- 沒有返回值,void類型的函數
- 不僅有聲明,還得要有實現
- 可以有參數,可以重載
4、信號與槽參數傳遞
4.1自定義一個帶參的信號
#ifndef MAINWINDOW_H
#define MAINWINDOW_Hclass MainWindow : public QMainWindow
{Q_OBJECT
public:MainWindow(QWidget *parent = nullptr);~MainWindow();//自定義一個帶參的信號
signals:void mysig(int a);//注意:信號與槽的參數類型必須匹配!!
//聲明一個帶參的槽函數
public slots: void getsig(int a); private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
4.2關聯帶參的信號與槽
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//關聯帶參的信號與槽,信號與槽的參數都需要在關聯是列舉出來 connect(this,SIGNAL(mysig(int)),this,SLOT(getsig(int)));
}MainWindow::~MainWindow()
{delete ui;
}
4.3發送一個帶參的信號
emit mysig(10010);
?注意事項:
- 信號參數的類型必須要與槽函數的類型匹配 參數類型不匹配會發生報錯: MainWindow::mysig(QString) --> MainWindow::myslot(int)
- 信號參數的個數必須大于槽函數參數的個數(理解:能少接受發來的信號,不能多接受發來的信號) 槽參數的個數大于信號參數個數 : MainWindow::mysig(int) --> MainWindow::myslot(int,int,int)
5、信號與槽的相互關聯
6、lambda表達式
- capture 子句(在 C++ 規范中也稱為 Lambda 引導。)
- 參數列表(可選)。 (也稱為 Lambda 聲明符)
- mutable 規范(可選)。
- 異常規范(可選)。
- 后面的-返回值-類型(可選)。
- Lambda 體。
語法:
auto func = [capture] (params) opt -> ret { func_body; };func是可以當作lambda表達式的名字,作為一個函數使用
capture是捕獲列表
params是參數表
opt是函數選項(mutable之類)
ret是返回值類型
func_body是函數體。 capture是捕獲列表:
[]不捕獲任何變量
[&]引用捕獲,捕獲外部作用域所有變量,在函數體內當作引用使用,可以修改值
[=]值捕獲,捕獲外部作用域所有變量,在函數內內有個副本使用 ,不可以修改值
[=, &a]值捕獲外部作用域所有變量,按引用捕獲a變量
[a]只值捕獲a變量,不捕獲其它變量
[this]捕獲當前類中的this指針opt選擇:
int a = 0;
auto f1 = [=](){ return a; }; // 值捕獲a
cout << f1() << endl;
auto f2 = [=]() { return a++; }; // 修改按值捕獲的外部變量,error
auto f3 = [=]() mutable { return a++; }; //添加mutable 選項可以修改
?lambda 表達式的應用
#include <iostream>
#include <list>
using namespace std;int main() {list<int> vec;vec.push_back(10);vec.push_back(45);vec.push_back(4);vec.push_back(48);vec.sort(); for(int i:vec){cout << i << endl;}//自定義排序的規則 vec.sort([](int a,int b){return a>b;});for(int i:vec){cout << i << endl;}
}
基礎寫法
?數據捕獲問題
?7、lambda 與 信號和槽
QT 中的一些簡單功能的槽函數可以直接設計為 lambda 表達式,這樣就不用在頭文件聲明槽,在源文件定義槽。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{ui->setupUi(this);//手動關聯信號與槽 , 去頭文件聲明 myslot ,再定義 myslot 很麻煩//connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::myslot);//把槽函數修改為 lambda表達式connect(ui->pushButton,&QPushButton::clicked,this,[](){qDebug() << "按鈕點擊";});}