參考視頻:黑馬程序員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
再在構造函數中實現兩個按鈕的功能(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 }
運行,進行測試:
實例二:自定義不帶參數信號處理
目的:實現兩個窗口,主窗口和子窗口,並且每個窗口都有一個按鍵,按鍵功能如下:
主窗口按鍵的功能:顯示子窗口,關閉父窗口;
子窗口按鍵的功能:關閉子窗口,顯示父窗口。
主窗口和子窗口的切換顯示全部由主窗口控制,可以理解為:主窗口的權限大於子窗口,子窗口的按鍵按下去只是產生一個信號,主窗口再對信號進行處理。
新建一個工程,工程創建之后,有以下文件,其中,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
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
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 }
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 }
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 }
運行測試:
點擊“切換子窗口”按鍵:
實例三:自定義帶參數信號處理
功能:在空白窗口中定義一個按鈕,點擊按鈕發送一個自定義的帶參數的信號,然后由本窗口接收信號並將參數打印出來。
首先,創建一個控件基類工程,創建后包含的文件如下:
在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
在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 }
運行,並進行測試,點擊一次發送按鈕,就會發送一個自定義信號,並接收到了它:
實例四: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
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 }
下面就簡單的說明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 :值傳遞時,默認變量為只讀的,如果需要在匿名函數中改變它,需要這個參數
運行代碼進行測試: