前言
作者:小蝸牛向前沖
名言:我可以接受失敗,但我不能接受放棄
??如果覺的博主的文章還不錯(cuò)的話,還請(qǐng)
點(diǎn)贊,收藏,關(guān)注??支持博主。如果發(fā)現(xiàn)有問題的地方歡迎?大家在評(píng)論區(qū)指正
本期學(xué)習(xí):什么是信號(hào)和槽,自定義槽函數(shù)和信號(hào)函數(shù),信號(hào)和槽的傳參,斷開,對(duì)lambda表達(dá)式的使用
目錄
一、信號(hào)和槽
1、信號(hào)和槽的理解
2、信號(hào)的本質(zhì)?
3、槽的本質(zhì)
二、信號(hào)和槽的使用?
1、 connect()函數(shù)
2、自定義槽函數(shù)二種實(shí)現(xiàn)方法
3、自定義信號(hào)
4、信號(hào)和槽的帶參傳遞?
三、 信號(hào)和槽的其他說明
1、信號(hào)與槽的斷開
2、使? Lambda 表達(dá)式定義槽函數(shù)
3、信號(hào)與槽的優(yōu)缺點(diǎn)
一、信號(hào)和槽
1、信號(hào)和槽的理解
在Qt中用戶和控件的每一次交互都稱為一個(gè)事件,?如 "?戶點(diǎn)擊按鈕" 是?個(gè)事件,"?戶關(guān)閉窗?" 也是?個(gè)事件。每個(gè)事件都回發(fā)送一個(gè)信號(hào),當(dāng)用戶點(diǎn)擊按鈕,就會(huì)發(fā)送按鈕被點(diǎn)擊的信號(hào)。
Qt中所有的控件都具備接收信號(hào)的能力,一個(gè)控件可以接受多種信號(hào),對(duì)每種信號(hào)都會(huì)做出相應(yīng)的響應(yīng)動(dòng)作。例如,按鈕所在的窗?接收到 "按鈕被點(diǎn)擊" 的信號(hào)后,會(huì)做 出 "關(guān)閉??" 的響應(yīng)動(dòng)作;在Qt中,對(duì)信號(hào)做出響應(yīng)動(dòng)作就稱為槽。
信號(hào)和槽是 Qt 特有的消息傳輸機(jī)制,它能將相互獨(dú)?的控件關(guān)聯(lián)起來。?如,"按鈕" 和 "窗?" 本?是兩個(gè)獨(dú)?的控件,點(diǎn)擊 "按鈕" 并不會(huì)對(duì) "窗?" 造成任何影響。通過信號(hào)和槽機(jī)制,可以將 "按 鈕" 和 "窗?" 關(guān)聯(lián)起來,實(shí)現(xiàn) "點(diǎn)擊按鈕會(huì)使窗?關(guān)閉" 的效果。
2、信號(hào)的本質(zhì)?
信號(hào)的本質(zhì)就是事件。
如:按鈕單擊、雙擊 ? 窗?刷新 ? ?標(biāo)移動(dòng)、?標(biāo)按下、?標(biāo)釋放 ? 鍵盤輸?
?信號(hào)的呈現(xiàn)形式就是函數(shù), 也就是說某個(gè)事件產(chǎn)?了, Qt 框架就會(huì)調(diào)?某個(gè)對(duì)應(yīng)的信號(hào)函數(shù), 通 知使?者。
3、槽的本質(zhì)
槽(Slot)就是對(duì)信號(hào)響應(yīng)的函數(shù)。槽就是?個(gè)函數(shù),與?般的 C++ 函數(shù)是?樣的,可以定義在 類的任何位置( public、protected 或 private ),可以具有任何參數(shù),可以被重載,也可以被直接調(diào) ?(但是不能有默認(rèn)參數(shù))。槽函數(shù)與?般的函數(shù)不同的是:槽函數(shù)可以與?個(gè)信號(hào)關(guān)聯(lián),當(dāng)信號(hào)被 發(fā)射時(shí),關(guān)聯(lián)的槽函數(shù)被?動(dòng)執(zhí)?
注意:
(1)信號(hào)和槽機(jī)制底層是通過函數(shù)間的相互
調(diào)?實(shí)現(xiàn)的。每個(gè)信號(hào)都可以?函數(shù)來表?,稱為信號(hào)函數(shù);每個(gè)槽也可以?函數(shù)表?,稱為槽函數(shù)。
例如: "按鈕被按下" 這個(gè)信號(hào)可以? clicked() 函數(shù)表 ?,"窗?關(guān)閉" 這個(gè)槽可以? close() 函數(shù)表?,假如使?信號(hào)和槽機(jī)制實(shí)現(xiàn):"點(diǎn)擊按鈕會(huì)關(guān)閉窗?" 的功能,其實(shí)就是 clicked() 函數(shù)調(diào)? close() 函數(shù)的效果。
(2)信號(hào)函數(shù)和槽函數(shù)通常位于某個(gè)類中,和普通的成員函數(shù)相?,它們的特別之處在于:
- 信號(hào)函數(shù)? signals 關(guān)鍵字修飾,槽函數(shù)? public slots、protected slots 或者 private slots 修 飾。signals 和 slots 是 Qt 在 C++ 的基礎(chǔ)上擴(kuò)展的關(guān)鍵字,專??來指明信號(hào)函數(shù)和槽函數(shù);
- ?信號(hào)函數(shù)只需要聲明,不需要定義(實(shí)現(xiàn)),?槽函數(shù)需要定義(實(shí)現(xiàn))。
二、信號(hào)和槽的使用?
1、 connect()函數(shù)
在 Qt 中,QObject 類提供了?個(gè)靜態(tài)成員函數(shù) connect() ,該函數(shù)專??來關(guān)聯(lián)指定的信號(hào)函數(shù)和槽函數(shù)。
connect() 函數(shù)原型:
?
connect(const QObject* sender,//信號(hào)的發(fā)送者(哪個(gè)控件)
const char* signal,//發(fā)送信息的函數(shù)
const QObject* receiver,//信號(hào)的接受者
const char* method,//接受信號(hào)的槽函數(shù)
Qt::ConnectionType type = Qt::AutoConnection);
//type: ?于指定關(guān)聯(lián)?式,默認(rèn)的關(guān)聯(lián)?式為 Qt::AutoConnection,通常不需要?動(dòng)設(shè)定。
代碼?例: 在窗?中設(shè)置?個(gè)按鈕,當(dāng)點(diǎn)擊 "按鈕" 時(shí)關(guān)閉 "窗?" .:
大家看到這里可能會(huì)有疑惑,為什么我們傳遞的參數(shù)類型沒有疑惑是對(duì)的,?我們明明是要給第一個(gè)參數(shù)(信號(hào)的發(fā)送者)傳給QObject類的,怎么就變成了傳QPushButton類呢?
這是因?yàn)樵赒T中QObject是所有類繼承的基類,通過層層的繼承關(guān)系,QPushButton也繼承了QObject,根據(jù)繼承關(guān)系這里也可以相當(dāng)與QObject使用,這里我們理解了參數(shù)1和參數(shù)3.
那為什么參數(shù)2和參數(shù)4明明傳遞的是一個(gè)函數(shù)指針,怎么能和char*類型的指針匹配。
其實(shí)最初的Qt為了能給信號(hào)參數(shù)和槽參數(shù)傳遞參數(shù),是要給這二個(gè)參數(shù)搭配二個(gè)厷
SIGBNAL和SLOT厷。
connect(but,SIGNAL(&QPushButton::licked),this,SLOT(&Widget::close));
?但是從Qt5開始就對(duì)是上面的內(nèi)容進(jìn)行了簡(jiǎn)單化,給connect提供了重載版本,其實(shí)參數(shù)2和參數(shù)4變成了泛形編程,就可以允許傳遞任意類型的函數(shù)指針。
QMetaObject::Connection QObject::connect(
const QObject *sender,
PointerToMemberFunction signal,
const QObject *receiver,
PointerToMemberFunction slot,
Qt::ConnectionType type = Qt::AutoConnection);
2、自定義槽函數(shù)二種實(shí)現(xiàn)方法
基本語法:
1. 包含Q_OBJECT宏
在你的類定義中,必須包含
Q_OBJECT
宏。這是因?yàn)?Q_OBJECT
宏允許類使用Qt的元對(duì)象系統(tǒng),包括信號(hào)和槽的機(jī)制。2. 類繼承
確保你的類繼承自
QObject
或其子類(如QWidget
、QMainWindow
等),這樣類才能支持信號(hào)和槽。3. 聲明槽函數(shù)
在類聲明中,槽函數(shù)可以在
public slots:
、protected slots:
或private slots:
部分聲明,這取決于你希望槽函數(shù)的訪問級(jí)別。4. 連接信號(hào)和槽
使用
QObject::connect
方法將信號(hào)連接到槽。
這里我們要完成在窗?中設(shè)置?個(gè)按鈕,當(dāng)點(diǎn)擊 "按鈕" 時(shí)改變窗口的名稱"。
方法1:代碼實(shí)現(xiàn):
這里我們要在widget.h頭文件中,對(duì)槽函數(shù)進(jìn)行聲明
?在widget.cpp中進(jìn)行對(duì)函數(shù)的編寫,這里我們讓如果開關(guān)被按下就對(duì)窗口進(jìn)行顯示更改為“按鈕已經(jīng)被按下"。
方法2:?通過圖形化界面
?這里會(huì)自動(dòng)幫我們生成一個(gè)函數(shù)
?函數(shù)名的說明
?這里我們發(fā)送,我們并沒有借助connect函數(shù)將信號(hào)和槽鏈接起來,但是其實(shí)Qt會(huì)通過函數(shù)名字自動(dòng)連接。
3、自定義信號(hào)
其實(shí)Qt中內(nèi)置的信號(hào),基本就夠覆蓋用戶的所以操作了。我們知道,信號(hào)的本質(zhì)其實(shí)就是函數(shù),也就是說如果我能要進(jìn)行自定義信號(hào),就需要自定義信號(hào)函數(shù)
在widget.h中,我們完成了對(duì)信號(hào)的定義
?在widget.cpp中調(diào)用connect完成對(duì)信號(hào)和槽的連接
4、信號(hào)和槽的帶參傳遞?
Qt 的信號(hào)和槽也?持帶有參數(shù), 同時(shí)也可以?持重載. 此處我們要求, 信號(hào)函數(shù)的參數(shù)列表要和對(duì)應(yīng)連接的槽函數(shù)參數(shù)列表?致. 此時(shí)信號(hào)觸發(fā), 調(diào)?到槽函數(shù)的時(shí)候, 信號(hào)函數(shù)中的實(shí)參就能夠被傳遞到槽函數(shù)的形參當(dāng)中。
在 "widget.h" 頭?件中聲明重載的信號(hào)函數(shù)以及重載的槽函數(shù)
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals:
void MySignal(const QString& text);
public:
void MYStols(const QString& text);
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
在 "Widget.cpp" ?件實(shí)現(xiàn)重載槽函數(shù)以及連接信號(hào)和槽。
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(this,&Widget::MySignal,this,&Widget::MYStols);
}
Widget::~Widget()
{
delete ui;
}
void Widget::MYStols(const QString & text)
{
this->setWindowTitle(text);
}
void Widget::on_pushButton_clicked()
{
//發(fā)出自定義的信號(hào)
//這里我們就可以通過信號(hào),把我們想要傳遞的參數(shù)給槽的回調(diào)函數(shù)
emit MySignal("信號(hào)發(fā)送");
}
點(diǎn)擊允許程序,在點(diǎn)擊按鈕輸出就可以改變窗口名稱?
對(duì)于這種帶參傳遞的作用最大的好處就是可以進(jìn)行進(jìn)行代碼復(fù)用,因?yàn)樾盘?hào)和槽的關(guān)系,可以是一對(duì)一,一對(duì)多的,多對(duì)多關(guān)系。也就是說,我們可以有多個(gè)信號(hào),但我點(diǎn)擊不同信號(hào)的時(shí)候,在同一槽中處理(回調(diào)函數(shù)),只是不同信號(hào),傳遞給槽函數(shù)的參數(shù)不同,從而達(dá)到代碼復(fù)用。
是我們要注意:信號(hào)傳遞給槽函數(shù)的參數(shù),可以多但是不能少。
多了就會(huì)用槽能接受幾個(gè)就用幾個(gè)但是少了一定是會(huì)報(bào)錯(cuò)誤的。
三、 信號(hào)和槽的其他說明
1、信號(hào)與槽的斷開
使? disconnect 即可完成斷開. disconnect 的?法和 connect 基本?致
在 "widget.h" 頭?件中聲明重載的信號(hào)函數(shù)以及重載的槽函數(shù)
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public:
void MySltos1();
void MySltos2();
private slots:
void on_pushButton_2_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
在 "Widget.cpp" ?件實(shí)現(xiàn)重載槽函數(shù)以及連接信號(hào)和槽。
?
#include "widget.h"
#include "ui_widget.h"
#include"QDebug"
#include"QPushButton"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->pushButton,&QPushButton::clicked,this,&Widget::MySltos1);
}
Widget::~Widget()
{
delete ui;
}
void Widget::MySltos1()
{
this->setWindowTitle("修改窗口1");
qDebug()<<"MySltos1修改";
}
void Widget::MySltos2()
{
this->setWindowTitle("修改窗口2");
qDebug()<<"MySltos2修改";
}
void Widget::on_pushButton_2_clicked()
{
//首先斷開連接
disconnect(ui->pushButton,&QPushButton::clicked,this,&Widget::MySltos1);
//然后重新綁定連接
connect(ui->pushButton,&QPushButton::clicked,this,&Widget::MySltos2);
}
這里我們?cè)试S程序,點(diǎn)擊修改,首先是窗口名稱變成?修改窗口1
當(dāng)我們切換修改就變?yōu)?,在點(diǎn)擊修改就變?yōu)樾薷拇翱??。
注意如果沒有用disconnect?斷開連接,在點(diǎn)擊切換后,會(huì)調(diào)用二個(gè)槽函數(shù)
2、使? Lambda 表達(dá)式定義槽函數(shù)
但如果想?便的編寫槽函數(shù),?如在編寫函數(shù)時(shí)連函數(shù)名都不想定義,則可以通過 Lambda表達(dá)式 來 達(dá)到這個(gè)?的。 Lambda表達(dá)式 是 C++11 增加的特性。C++11 中的 Lambda表達(dá)式 ?于定義并創(chuàng)建匿名的函數(shù)對(duì) 象,以簡(jiǎn)化編程?作。
對(duì)于lambda表達(dá)式這里進(jìn)行簡(jiǎn)單介紹:
Lambda表達(dá)式 的語法格式如下:
[ capture ] ( params ) opt -> ret {
Function body;
};
- capture 捕獲列表
- params 參數(shù)表
- opt 函數(shù)選項(xiàng)
- ret 返回值類型
- Function body 函數(shù)
?局部變量引??式 [ ]
符號(hào) | 說明 |
[ ] | 局部變量捕獲列表。Lambda表達(dá)式不能訪問外部函數(shù)體的任何局部變量 |
[a] | 在函數(shù)體內(nèi)部使?值傳遞的?式訪問a變量 |
[&b] | 在函數(shù)體內(nèi)部使?引?傳遞的?式訪問b變量 |
[=] | 函數(shù)外的所有局部變量都通過值傳遞的?式使?, 函數(shù)體內(nèi)使?的是副本 |
[&] | 以引?的?式使?Lambda表達(dá)式外部的所有變量 |
[=, &foo] | foo使?引??式, 其余是值傳遞的?式 |
[&, foo] | foo使?值傳遞?式,其余引?傳遞 |
[this] | 在函數(shù)內(nèi)部可以使?類的成員函數(shù)和成員變量,= 和 & 形式也都會(huì)默認(rèn)引? |
?
運(yùn)用實(shí)例:
3、信號(hào)與槽的優(yōu)缺點(diǎn)
優(yōu)點(diǎn): 松散耦合
信號(hào)發(fā)送者不需要知道發(fā)出的信號(hào)被哪個(gè)對(duì)象的槽函數(shù)接收,槽函數(shù)也不需要知道哪些信號(hào)關(guān)聯(lián)了??,Qt的信號(hào)槽機(jī)制保證了信號(hào)與槽函數(shù)的調(diào)?。?持信號(hào)槽機(jī)制的類或者?類必須繼承于 QObject 類
缺點(diǎn): 效率較低文章來源:http://www.zghlxwxcb.cn/news/detail-860776.html
與回調(diào)函數(shù)相?,信號(hào)和槽稍微慢?些,因?yàn)樗鼈兲峁┝烁?的靈活性,盡管在實(shí)際應(yīng)?程序中差別不大。通過信號(hào)調(diào)?的槽函數(shù)?直接調(diào)?的速度慢約10倍(這是定位信號(hào)的接收對(duì)象所需的開銷;遍歷所有關(guān)聯(lián);編組/解組傳遞的參數(shù);多線程時(shí),信號(hào)可能需要排隊(duì)),這種調(diào)?速度對(duì)性能要求不是 ?常?的場(chǎng)景是可以忽略的,是可以滿?絕?部分場(chǎng)景。文章來源地址http://www.zghlxwxcb.cn/news/detail-860776.html
到了這里,關(guān)于[Qt的學(xué)習(xí)日常]--信號(hào)和槽的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!