Qt自定義信號和槽 記錄

#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.hteacher.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;
}

執行!
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章