Qt信號與槽的使用


參考視頻:黑馬程序員https://www.bilibili.com/video/BV1XW411x7NU?p=4

1  新建工程

先創建一個控件基礎工程,創建后的界面如下:

主函數我們不需要修改,就保持這樣,對於C++的知識我不太理解。

上述代碼中,執行到第7行的時候,會先去執行基類的構造函數,再執行MyWidget類的構造函數。我們只需要在構造函數中實現需要實現的功能。

構造函數對應在mywidget.cpp中:

2  測試代碼

實例一:標准的信號處理

測試目的:在主窗口中,新建兩個按鈕,功能如下:

按鈕一的功能:按下按鈕,關閉主窗口;

按鈕二的功能:釋放按鈕,更改按鈕二的文本,並隱藏按鈕一。

由於在實現過程中,會用到信號與槽的知識,就先簡單介紹一下基本知識,可能不正確,這只是我個人的理解:

信號:某一事件發生時產生,用於表示一個事件發生了。

槽:就是信號處理函數,用於指示當信號發生時,需要做出什么動作。

其中,我們connect函數來連接信號與槽之間的關系,函數的原型如下:

connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection);

舉例說明:

connect(&b1, &QPushButton::pressed, this, &MyWidget::close);

/* &b1:信號發出者,指針類型

* &QPushButton::pressed:處理的信號,&發送者的類名::信號名字

* this:信號接收者

* &MyWidget::close:槽函數,信號處理函數 &接收的類名::槽函數名字

*/

不同的控件有哪些信號,可通過幫助文檔查看,以QPushButton為例進行說明(點QPushButton,再按F1):

這里沒有看到signal函數,可能是從它的父類繼承過來的,我們再看一下它的父類:

 實現的相關代碼

 先在MyWidget類中實現兩個按鈕(mywidget.h):

 1 #ifndef MYWIDGET_H
 2 #define MYWIDGET_H
 3 
 4 #include <QWidget>
 5 #include <QPushButton>
 6 
 7 class MyWidget : public QWidget
 8 {
 9     Q_OBJECT
10 
11 public:
12     MyWidget(QWidget *parent = 0);
13     ~MyWidget();
14 
15 private:
16     QPushButton b1;
17     QPushButton *b2;
18 
19     void myslot();
20 
21 };
22 
23 #endif // MYWIDGET_H
View Code

再在構造函數中實現兩個按鈕的功能(mywidget.cpp):

 1 #include "mywidget.h"
 2 #include <QPushButton>
 3 
 4 MyWidget::MyWidget(QWidget *parent)
 5     : QWidget(parent)
 6 {
 7     b1.setParent(this);
 8     b1.setText("按鈕一");
 9     b1.move(100, 100);
10 
11     b2 = new QPushButton(this);
12     b2->setText("按鈕二");
13 
14     connect(&b1, &QPushButton::pressed, this, &MyWidget::close);
15     /* &b1:信號發出者,指針類型
16     *  &QPushButton::pressed:處理的信號,&發送者的類名::信號名字
17     *  this:信號接收者
18     *  &MyWidget::close:槽函數,信號處理函數 &接收的類名::槽函數名字
19     */
20 
21     /*
22      * 自定義槽,普通函數的用法
23      * Qt5:任意的成員函數,普通全局函數,靜態函數
24      * 槽函數需要和信號一致(參數、返回值)
25      * 由於信號都是沒有返回值,所以槽函數一定沒有返回值
26      */
27      connect(b2, &QPushButton::released, this, &MyWidget::myslot);
28 
29      connect(b2, &QPushButton::released, &b1, &MyWidget::hide);
30     /*
31      * 信號:短信
32      * 槽函數:接收短信的手機
33     */
34 }
35 
36 void MyWidget::myslot()
37 {
38     b2->setText("123");
39 }
40 
41 MyWidget::~MyWidget()
42 {
43 
44 }
View Code

運行,進行測試:

 實例二:自定義不帶參數信號處理

目的:實現兩個窗口,主窗口和子窗口,並且每個窗口都有一個按鍵,按鍵功能如下:

主窗口按鍵的功能:顯示子窗口,關閉父窗口;

子窗口按鍵的功能:關閉子窗口,顯示父窗口。

主窗口和子窗口的切換顯示全部由主窗口控制,可以理解為:主窗口的權限大於子窗口,子窗口的按鍵按下去只是產生一個信號,主窗口再對信號進行處理。

新建一個工程,工程創建之后,有以下文件,其中,subwindown相關文件是通過點擊signal_slot_2目錄文件,選擇添加新文件,選擇C++ --> C++ Class,基類我們選擇QWidget:

 實現的代碼如下:

widget.h是widget類所在同文件,主要實現:聲明主窗口按鍵處理函數、聲明子窗口信號接收處理函數、實例化一個subwindown類對象、實例化一個QPushButton類對象。

 1 #ifndef WIDGET_H
 2 #define WIDGET_H
 3 
 4 #include <QWidget>
 5 #include <QPushButton>
 6 #include "subwindown.h"
 7 
 8 class Widget : public QWidget
 9 {
10     Q_OBJECT
11 
12 public:
13     Widget(QWidget *parent = 0);
14     ~Widget();
15 
16     void my_slot();
17     void dealsub();
18 
19 private:
20     QPushButton b_main;
21 
22     subwindown sw;
23 };
24 
25 #endif // WIDGET_H
View Code

subwindown.h是subwindown類所在頭文件,主要實現:聲明子窗口按鍵處理函數、聲明一個信號、實例化一個QPushButton類對象。

 1 #ifndef SUBWINDOWN_H
 2 #define SUBWINDOWN_H
 3 
 4 #include <QWidget>
 5 #include <QPushButton>
 6 
 7 class subwindown : public QWidget
 8 {
 9     Q_OBJECT
10 public:
11     explicit subwindown(QWidget *parent = nullptr);
12     //定義槽函數
13     void sendslot();
14 
15 signals:
16     /*
17     * 信號必須有signals關鍵字聲明
18     * 信號沒有返回值,但可以有參數
19     * 信號就是函數的聲明,只需聲明,無需定義
20     * 使用:emit mysignal();
21     */
22     void mysignal();
23 
24 public slots:
25 
26 private:
27     QPushButton b_sub;
28 
29 };
30 
31 #endif // SUBWINDOWN_H
View Code

main.cpp中的代碼不改動,就使用生成的代碼:

 1 #include "widget.h"
 2 #include <QApplication>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     QApplication a(argc, argv);
 7     Widget w;
 8     w.show();
 9 
10     return a.exec();
11 }
View Code

widget.cpp中實現的是主窗口的構造函數,主要實現:接收主窗口按鍵的信號並處理、接收子窗口發送的信號並處理。

 1 #include "widget.h"
 2 
 3 Widget::Widget(QWidget *parent)
 4     : QWidget(parent)
 5 {
 6     setWindowTitle("主窗口");
 7 
 8     //設置按鈕相關屬性
 9     b_main.setParent(this);
10     b_main.setText("切換子窗口");
11     b_main.move(50, 50);
12     //處理主窗口的按鈕所產生的信號
13     connect(&b_main, &QPushButton::clicked, this, Widget::my_slot);
14 
15     //接收子窗口信號,並進行處理
16     connect(&sw, &subwindown::mysignal, this, &Widget::dealsub);
17     resize(400, 300);
18 }
19 
20 void Widget::my_slot()
21 {
22     //顯示子窗口
23     sw.show();
24     //父窗口隱藏
25     this->hide();
26 }
27 
28 void Widget::dealsub()
29 {
30     //主窗口顯示
31     this->show();
32     //子窗口隱藏
33     sw.hide();
34 }
35 
36 Widget::~Widget()
37 {
38 
39 }
View Code

subwindown.cpp中實現的是子窗口的構造函數,主要實現:接收子進程按鍵的信號並處理,處理方式為發送一個自定義信號。

 1 #include "subwindown.h"
 2 
 3 subwindown::subwindown(QWidget *parent) : QWidget(parent)
 4 {
 5     setWindowTitle("子窗口");
 6 
 7     //按鍵屬性設置
 8     b_sub.setText("切換主窗口");
 9     b_sub.setParent(this);
10     b_sub.move(50, 50);
11 
12     //接收按鍵信號並處理
13     connect(&b_sub, &QPushButton::clicked, this, &subwindown::sendslot);
14     resize(400, 300);
15 }
16 
17 void subwindown::sendslot()
18 {
19     //發送信號
20     emit mysignal();
21 }
View Code

運行測試:

點擊“切換子窗口”按鍵:

實例三:自定義帶參數信號處理

功能:在空白窗口中定義一個按鈕,點擊按鈕發送一個自定義的帶參數的信號,然后由本窗口接收信號並將參數打印出來。

首先,創建一個控件基類工程,創建后包含的文件如下:

在widget.h中,實現的功能有:聲明一個發送信號函數、聲明一個接收信號函數、自定義一個帶參數的信號、實例化一個QPushButton對象。

 1 #ifndef WIDGET_H
 2 #define WIDGET_H
 3 
 4 #include <QWidget>
 5 #include <QPushButton>
 6 
 7 class Widget : public QWidget
 8 {
 9     Q_OBJECT
10 
11 public:
12     Widget(QWidget *parent = 0);
13     ~Widget();
14 
15     //點擊按鈕,發送信號函數
16     void send_signal();
17     //接收信號處理函數
18     void recv_signal(int, QString);
19 
20 signals:
21     //自定義一個帶參數的信號
22     void mysignal(int, QString);
23 
24 private:
25     QPushButton b_main;
26 
27 };
28 
29 #endif // WIDGET_H
View Code

在widget.cpp中,實現的功能有:接收點擊按鍵的信號並進行處理,接收自定義的信號並進行處理。

 1 #include "widget.h"
 2 #include <QDebug>
 3 
 4 Widget::Widget(QWidget *parent)
 5     : QWidget(parent)
 6 {
 7     b_main.setParent(this);
 8     b_main.setText("發送");
 9     b_main.move(100, 100);
10 
11     //點擊按鈕,發送信號
12     connect(&b_main, &QPushButton::clicked, this, &Widget::send_signal);
13 
14     //接收點擊按鈕,發送的信號
15     void (Widget::*testsignal)(int, QString) = &Widget::mysignal;
16     connect(this, testsignal, this, &Widget::recv_signal);
17 
18     this->resize(300, 300);
19 }
20 
21 void Widget::send_signal()
22 {
23     emit mysignal(100, "我已經發送信號");
24 }
25 
26 void Widget::recv_signal(int a, QString str)
27 {
28     qDebug() << a << str;
29 }
30 
31 Widget::~Widget()
32 {
33 
34 }
View Code

運行,並進行測試,點擊一次發送按鈕,就會發送一個自定義信號,並接收到了它:

實例四:lambda表達式的使用 

功能:創建一個按鈕,點擊按鈕發送一個信號,不需要指定信號接收函數和信號接收者,直接使用匿名函數(lambda表達式)實現。

先新建一個工程,新建后的工程文件如下:

由於lambda是C++11支持的特性,所以我們需要在lambda_test.pro文件末尾添加一句:CONFIG += C++11

先把代碼放上,再說明lambda表達式的作用。

widget.h文件:

 1 #ifndef WIDGET_H
 2 #define WIDGET_H
 3 
 4 #include <QWidget>
 5 #include <QPushButton>
 6 
 7 class Widget : public QWidget
 8 {
 9     Q_OBJECT
10 
11 public:
12     Widget(QWidget *parent = 0);
13     ~Widget();
14 
15 private:
16     //定義一個類中成員變量
17     int a = 10;
18 
19 };
20 
21 #endif // WIDGET_H
View Code

widget.cpp文件:

 1 #include "widget.h"
 2 #include <QDebug>
 3 
 4 Widget::Widget(QWidget *parent)
 5     : QWidget(parent)
 6 {
 7     QPushButton *b_main = new QPushButton(this);
 8     b_main->setParent(this);
 9     b_main->setText("開始");
10     b_main->move(100, 100);
11 
12     //定義一個外部局部變量
13     int b = 12;
14     //Lambda表達式,匿名函數對象
15     //C++11增加的新特性,項目文件: CONFIG += C++11
16     //Qt配合信號一起使用,非常方便
17     connect(b_main, &QPushButton::clicked,
18         // =:把外部所有局部變量、類中所有成員以值方式傳進來
19         // this:類中所有成員以值傳遞方式
20         // &:引用符號,外部所有局部變量
21         [=](bool isCheck)mutable
22         {
23             b_main->setText("lambda表達式");
24             qDebug() << "已經進入lambda表達式";
25             qDebug() << a << b;
26             a += 10;
27             b += 20;
28             qDebug() << isCheck;
29         }
30     );
31 
32     this->resize(300, 300);
33 }
34 
35 Widget::~Widget()
36 {
37 
38 }
View Code

下面就簡單的說明lambda表達式的語法,我也不是很懂,根據測試結果進行說明。

參考了這篇博客:https://www.cnblogs.com/rainbow70626/p/10328143.html

格式:[capture](parameters) mutable ->return-type{statement};

capture:捕捉列表,也單獨代表函數的開始,主要有以下使用方式:

  • 單獨傳遞外部變量,如:[b_main]
  • =:把外部所有局部變量、類中所有成員以值方式傳進來(widget.c和widget.h文件中的成員)
  • this:類中所有成員以值傳遞方式(widget.h文件中的成員)
  • &:引用符號,外部所有局部變量(widget.c文件中的成員),當變量是指針時,最好別用這個。

parameters:參數列表,信號的參數。

mutable :值傳遞時,默認變量為只讀的,如果需要在匿名函數中改變它,需要這個參數

運行代碼進行測試:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM