文章目錄
- 前言
- 一、信號的本質
- 二、槽的本質
- 三、 信號和槽的使?
- 3.1 連接信號和槽
- 四、使用步驟
- 4.1 通過QtCreator?成信號槽代碼
- 五、 ?定義信號和槽
- 5.1 ?例1:信號和槽函數初步使用
- 5.2 ?例2 兩個類使用
- 5.3 示例3 按鈕使用觸發信號
- 六、 帶參數的信號和槽
- 6.1 ?例1:重載信號槽
- 6.2 ?例2:信號槽參數列表匹配規則
- 6.3 ?例3:信號的參數個數可以多于槽函數的參數個數,但是槽的參數個數不能多于信號參數個數
- 🚩總結
前言
在Qt中,??和控件的每次交互過程稱為?個事件。?如"??點擊按鈕"是?個事件,"??關閉窗?"也是?個事件。每個事件都會發出?個信號,例如??點擊按鈕會發出"按鈕被點擊"的信號,??關閉窗?會發出"窗?被關閉"的信號。
Qt 中的所有控件都具有接收信號的能?,?個控件還可以接收多個不同的信號。對于接收到的每個信號,控件都會做出相應的響應動作。例如,按鈕所在的窗?接收到"按鈕被點擊"的信號后,會做出"關閉??"的響應動作;再?如輸?框??接收到"輸?框被點擊"的信號后,會做出"顯?閃爍的
光標,等待??輸?數據"的響應動作。在Qt中,對信號做出的響應動作就稱之為槽。
信號和槽是Qt特有的消息傳輸機制,它能將相互獨?的控件關聯起來。?如,"按鈕"和"窗?"本?是兩個獨?的控件,點擊"按鈕"并不會對"窗?"造成任何影響。通過信號和槽機制,可以將"按鈕"和"窗?"關聯起來,實現"點擊按鈕會使窗?關閉"的效果
一、信號的本質
信號是由于??對窗?或控件進?了某些操作,導致窗?或控件產?了某個特定事件,這時Qt對
應的窗?類會發出某個信號,以此對??的操作做出反應。因此,信號的本質就是事件。如:
- 按鈕單擊、雙擊
- 窗?刷新
- ?標移動、?標按下、?標釋放
- 鍵盤輸?
那么在Qt中信號是通過什么形式呈現給使?者的呢? - 我們對哪個窗?進?操作,哪個窗?就可以捕捉到這些被觸發的事件。
- 對于使?者來說觸發了?個事件我們就可以得到Qt框架給我們發出的某個特定信號。
- **信號的呈現形式就是函數,**也就是說某個事件產?了,Qt框架就會調?某個對應的信號函數,通知使?者。
在Qt中信號的發出者是某個實例化的類對象。
二、槽的本質
**槽(Slot)就是對信號響應的函數。**槽就是?個函數,與?般的C++函數是?樣的,可以定義在類的任何位置(public、protected或private),可以具有任何參數,可以被重載,也可以被直接調?(但是不能有默認參數)。槽函數與?般的函數不同的是:槽函數可以與?個信號關聯,當信號被發射時,關聯的槽函數被?動執?。
說明
(1)信號和槽機制底層是通過函數間的相互調?實現的。每個信號都可以?函數來表?,稱為信號函數;**每個槽也可以?函數表?,稱為槽函數。**例如:"按鈕被按下"這個信號可以?clicked()函數表?,"窗?關閉"這個槽可以?close()函數表?,假如使?信號和槽機制
實現:"點擊按鈕會關閉窗?"的功能,其實就是clicked()函數調?close()函數的效果。
(2)信號函數和槽函數通常位于某個類中,和普通的成員函數相?,它們的特別之處在于:
- 信號函數? signals關鍵字修飾,槽函數?
publicslots
、protectedslots
或者privateslots
修飾。signals
和slots
是Qt
在C++
的基礎上擴展的關鍵字,專??來指明信號函數和槽函數;
信號函數只需要聲明,不需要定義(實現),?槽函數需要定義(實現)。
信號函數的定義是
Qt
?動在編譯程序之前?成的.編寫Qt應?程序的程序猿?需關注
這種?動?成代碼的機制稱為元編程(MetaProgramming).這種操作在很多場景中都能?到.
三、 信號和槽的使?
3.1 連接信號和槽
代碼如下(示例):
在Qt
中,QObject
類提供了?個靜態成員函數connect()
,該函數專??來關聯指定的信號函數和槽
函數。
關于
QObject
QObject
是Qt內置的?類.Qt中提供的很多類都是直接或者間接繼承?QObject
.
這?點的設定和Java是?常相似的.
connect()
函數原型:
// 普通成員函數作為槽
template<typename Func1, typename Func2>
QMetaObject::Connection connect(const QObject *sender, // 信號發送對象Func1 signal, // 發送的信號(函數指針)const QObject *receiver, // 信號接收對象Func2 slot, // 接收的槽函數(函數指針)Qt::ConnectionType type = Qt::AutoConnection // 連接類型
);// 靜態成員函數作為槽
template<typename Func1, typename Func2>
QMetaObject::Connection connect(const QObject *sender, Func1 signal, Func2 slot, Qt::ConnectionType type = Qt::AutoConnection
);
connect (const Q0bject *sender, 、//sender:信號的發送者;const char * signal , //signal:發送的信號(信號函數);const Q0bject * receiver , //receiver:信號的接收者;const char *method , //method:接收信號的槽函數;Qt: :ConnectionType type = Qt: :AutoConnection )type:?于指定關聯?式,默認的關聯?式為Qt::AutoConnection,通常不需要?動設定。
**代碼示例:**在窗口中設置一個按鈕,當點擊"按鈕"時關閉"窗口".
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{QPushButton * btn = new QPushButton("關閉按鈕");//創建按鈕resize(800, 600); //調整窗口大小//關聯信號和槽,實現點擊“按鈕”, 關閉“窗口”connect(btn, &QPushButton::clicked, this, &QWidget::close);}
2.2 查看內置信號和槽
系統?帶的信號和槽通常是通過"**Qt幫助?檔"**來查詢。
如上述?例,要查詢"按鈕"的信號,在幫助?檔中輸?:QPushButton,
- ?先可以在"
Contents
"中尋找關鍵字signals
,
如果沒有找到,繼續去?類中查找.因此我們去他的?類QAbstractButton
中繼續查找關鍵字signals
,
這?的clicked()
就是要找的信號。槽函數的尋找?式和信號?樣,只不過它的關鍵字是slot
。
四、使用步驟
4.1 通過QtCreator?成信號槽代碼
Qt Creator 可以快速幫助我們?成信號槽相關的代碼.
**代碼?例:**在窗?中設置?個按鈕,當點擊"按鈕"時關閉"窗?".
注意:創建時要?成UI設計?件;
- 雙擊widget.ui?件,進?UI設計界?;
-
在U設計窗口中拖入一個"按鈕",并且修改"按鈕"的名稱及字體大小等;
-
可視化生成槽函數;
當單擊"轉到槽…"之后,出現如下界面:對于按鈕來說,當點擊時發送的信號是: clicked()
,所以此處選擇: clicked()
對于普通按鈕來說,使用
clicked
信號即可.clicked (bool)
沒有意義的.具有特殊狀態的按鈕(比如復選按鈕)才會用到clicked ( bool)]
.
- ?動?成槽函數原型框架;
(1)在"widget.h"頭文件中自動添加槽函數的聲明;
說明:
?動?成槽函數的名稱有?定的規則。槽函數的命名規則為:on_XXX_SSS,其中:
1、以"on
"開頭,中間使?下劃線連接起來;
2、"XXX
"表?的是對象名(控件的objectName
屬性)。
3、"SSS
"表?的是對應的信號。
如:“on_pushButton_clicked()
”,pushButton
代表的是對象名,clicked
是對應的信號。
按照這種命名?格定義的槽函數,就會被Qt?動的和對應的信號進?連接.
但是咱們?常寫代碼的時候,除?是IDE?動?成,否則最好還是不要依賴命名規則,?是顯式使?connect更好.
???顯式connect可以更清晰直觀的描述信號和槽的連接關系.
另???也防?信號或者槽的名字拼寫錯誤導致連接失效.
(當然,是配置?于約定,還是約定?于配置,哪種更好,這樣的話題業界尚存在爭議.此處我個
?還是更建議優先考慮顯式connect)
(2)在"widget.cpp"中?動?成槽函數定義.
6、在槽函數函數定義中添加要實現的功能.實現關閉窗口的效果.
五、 ?定義信號和槽
基本語法
在Qt中,允許?定義信號的發送?以及接收?,即可以?定義信號函數和槽函數。但是對于?定義的信號函數和槽函數有?定的書寫規范。
1、?定義信號函數書寫規范
(1)?定義信號函數必須寫到"signals"下;
(2)返回值為void,只需要聲明,不需要實現;
(3)可以有參數,也可以發?重載;
2、?定義槽函數書寫規范
(1)早期的Qt版本要求槽函數必須寫到"publicslots"下,但是現在?級版本的Qt允許寫到類的"public" 作?域中或者全局下;
(2)返回值為void,需要聲明,也需要實現;
(3)可以有參數,可以發?重載
3、發送信號
使?"emit
"關鍵字發送信號。"emit
"是?個空的宏。"emit
"其實是可選的,沒有什么含義,只是為了提醒開發?員。
5.1 ?例1:信號和槽函數初步使用
1、在widget.h
中聲明?定義的信號和槽,如圖所?;
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void EmitSignal();signals:void MySignal(); //信號聲明public slots:void MySlots(); //槽聲明private:Ui::Widget *ui;
};
#endif // WIDGET_H
2、在widget.cpp中實現槽函數,并且關聯信號和槽
注意:圖中的①和②的順序不能顛倒。
原因是,?先關聯信號和槽,?旦檢測到信號發射之后就會??執?關聯的槽函數。反之,若先發射
信號,此時還沒有關聯槽函數,當信號發射之后槽函數不會響應.
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{//關聯自定義的信號和槽connect(this, &Widget::MySignal, this, &Widget::MySlots);//發射信號EmitSignal();ui->setupUi(this);
}void Widget::MySlots()
{qDebug() <<"我的信號和槽";
}void Widget::EmitSignal()
{emit MySignal();
}Widget::~Widget()
{delete ui;
}
5.2 ?例2 兩個類使用
?例2:當?師說"上課了",學?們就"回到座位,開始學習"
1、在源文件中新建兩個類,一個是老師類,一個是學生類;首先選中項目名稱,鼠標右鍵----->“addnew…”
點擊"addnew…"之后,出現如下界?:
選擇"choose
"出現如下界?.
注意:
在Qt中新建類時,要選擇新建類的?類.
顯然,當前項?中還沒啥類適合做新類的?類,同時新的類也不是?個"窗?"或者"控件".這種情況?般選擇QObject作為基類
這樣做的好處是這個新類的對象可以搭配Qt的對象樹機制.便于對象的正確釋放
選擇"下一步",出現如下界面:
對于"學?類"以上述同樣的?式進?添加,添加完成之后,項??錄新增?件如下:
在teacher.h中聲明信號函數:
#ifndef TEACHER_H
#define TEACHER_H#include <QObject>class Teacher : public QObject
{Q_OBJECT
public:explicit Teacher(QObject *parent = nullptr);signals:void MySignal(); //自定義信號函數聲明
};#endif // TEACHER_H
在student.h中聲明槽函數:
#ifndef STUDENT_H
#define STUDENT_H#include <QObject>class Student : public QObject
{Q_OBJECT
public:explicit Student(QObject *parent = nullptr);signals:public slots:void StartStudy(); //自定義槽函數
};#endif // STUDENT_H
在widget.h中實例化"?師類對象"和"學?類對象";
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "student.h"
#include "teacher.h"QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void EmitSignal();
private:Teacher *tch;Student *stu;Ui::Widget *ui;
};
#endif // WIDGET_H
在student.cpp中實現槽函數:
#include "student.h"
#include <QDebug>Student::Student(QObject *parent): QObject{parent}
{}void Student::StartStudy()
{qDebug() << "回到座位,繼續學習";
}
在widget.cpp中連接?定義信號和槽;
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{this->tch = new Teacher(this);this->stu = new Student(this);connect(tch, &Teacher::MySignal, stu, &Student::StartStudy);EmitSignal();ui->setupUi(this);
}void Widget::EmitSignal()
{emit tch->MySignal();
}Widget::~Widget()
{delete ui;
}
運?結果如下圖?:
5.3 示例3 按鈕使用觸發信號
示例3:老師點擊"按鈕"觸發學生上課;
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{this->tch = new Teacher(this);this->stu = new Student(this);QPushButton * btn = new QPushButton("上課了", this);resize(800, 600);btn->move(100, 100);connect(tch, &Teacher::MySignal, stu, &Student::StartStudy);connect(btn, &QPushButton::clicked, tch, &Teacher::MySignal);EmitSignal();ui->setupUi(this);
}void Widget::EmitSignal()
{emit tch->MySignal();
}Widget::~Widget()
{delete ui;
}
運?結果如下圖?:
六、 帶參數的信號和槽
Qt 的信號和槽也?持帶有參數,同時也可以?持重載.
此處我們要求,信號函數的參數列表要和對應連接的槽函數參數列表?致
此時信號觸發,調?到槽函數的時候,信號函數中的實參就能夠被傳遞到槽函數的形參當中.
通過這樣的機制,就可以讓信號給槽傳遞數據了.
6.1 ?例1:重載信號槽
(1)在"widget.h"頭?件中聲明重載的信號函數以及重載的槽函數;如下圖所?:
(2)在"Widget.cpp"?件實現重載槽函數以及連接信號和槽。
注意:在定義函數指針時要指明函數指針的作?域。
(3)執?結果如下圖所?
6.2 ?例2:信號槽參數列表匹配規則
1、在"widget.h"頭?件中聲明信號和槽函數;
2、在"widget.cpp"?件中實現槽函數以及連接信號和槽;
其實信號的參數個數可以多于槽函數的參數個數,但是槽的參數個數不能多于信號參數個數.
但是實際開發中最好還是保持參數個數也能匹配?致.
6.3 ?例3:信號的參數個數可以多于槽函數的參數個數,但是槽的參數個數不能多于信號參數個數
1、在"widget.h"頭?件中聲明信號和槽函數;
2、在"widget.cpp"?件中實現槽函數以及連接信號和槽;