#0前言
做程序不可能只是用自帶的信號和槽對吧,得自定義,怎麼自定義?
視頻:https://www.bilibili.com/video/BV1g4411H78N?p=10(瘋狂暗示😏)
倉庫(自定義信號槽,快⭐️):https://github.com/Github-Programer/Qt-Notes/tree/master/Qt/04_initSignalsAndSlot
複習單詞:signals、slots
新單詞:emit
#1創建
新建一個項目,名稱:02_SignalsAndSlot(可自定義)
背景:下課後,老師觸發一個信號->餓了,學生響應信號->請客喫飯
增加兩個類:Teacher、Student(新建C++ Class類)
命名爲Teacher和Student,分別兩個類,需要上傳到Git的同學可以選擇Git工具
過程中要繼承QObject類,這樣子不用管釋放問題
#2初始
進入一個.h文件,會發現類中有幾個部分:
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
//自定義信號
};
#endif // STUDENT_H
signals部分就是寫自定義信號的地方,slots老版本是自帶的,我這個沒有(高版本),老版本可以自己寫
改成:
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
//自定義信號
public slots:
//自定義槽函數
};
#endif // STUDENT_H
把Student.h和Teacher.h都改成類似的
#3關於自定義信號槽的說明
- 自定義信號
- 需要寫在
signals:
下 - 返回值是void,只需要聲明,不需要實現
- 可以有參數,所以可以重載
- 需要寫在
- 自定義槽函數
- 早期Qt版本必須需要寫在public slots下,高級版本(例如Qt5)可以寫到 public或者全局,但是我喜歡寫成早期版本的樣子,因爲我覺得這樣子更清晰
- 返回值 void ,需要聲明,也需要實現
#4自定義信號
那麼老師觸發的信號是餓了,不需要參數,於是函數聲明如下
Teacher.h
...
signals:
void hungry();
public slots:
//自定義槽函數
};
...
#5自定義槽
在類中聲明
public slots:
//自定義槽函數
void treat(); //聲明請客函數
還需要在student.cpp中實現
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent) //構造方法
{
}
void Student::treat() //實現
{
qDebug() << "請老師喫飯" << endl;
//實現不需要太複雜,爲了練習
}
#6實現
去Widget.h裏,引入student.h
和teacher.h
頭文件。
然後在類中(私有共有都可以)加入兩個對象
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "teacher.h"
#include "student.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
Teacher * tc;
Student * st;
};
#endif // WIDGET_H
然後還需要在Widget.cpp中new這個對象對吧
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//創建一個老師對象
this->tc = new Teacher(this);
//創建一個學生對象
this->st = new Student(this);
}
Widget::~Widget()
{
delete ui;
}
然後我們需要建立連接,使用connect方法如下
//老師餓了 學生請客連接==
connect(tc, &Teacher::hungry, st, &Student::treat);
忘了說了,槽函數的智能提示圖標是一個卡槽
然後你運行😏[壞笑].png
#7錯誤改進
我們發現運行沒有問題,但是什麼都沒有顯示?什麼問題?
因爲這個連接是沒有任何問題的,但是老師“不餓”!老師不可能永遠餓着吧……
咱們上次說過,點擊按鈕關閉窗口,按鈕是發送者,你點擊是觸發,你不點擊窗口不會無緣無故關閉掉,所以發送者沒有觸發!所以,沒有下課後這個條件,老師也不會餓了😸
那看來我們需要自己寫一個下課了的方法來設置前提條件(發送者)
還是寫在Widget.h文件中的Private中,加一個聲明:classIsOver
private:
Ui::Widget *ui;
Teacher * tc;
Student * st;
void classIsOver(); //下課了條件
然後記住一個關鍵字:emit 觸發
,可以使用emit關鍵字觸發信號
更改widget.cpp
再在程序中調用一下這個函數,就可以了,widget.cpp完整代碼
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//創建一個老師對象
this->tc = new Teacher(this);
//創建一個學生對象
this->st = new Student(this);
//老師餓了 學生請客連接==
connect(tc, &Teacher::hungry, st, &Student::treat);
//調用下課函數
classIsOver();
}
void Widget::classIsOver()
{
//下課函數 調用後 觸發老師餓了的信號
emit tc->hungry(); //成功觸發 使用emit關鍵字
}
Widget::~Widget()
{
delete ui;
}
執行!