1. 程式人生 > >QT學習---day2---訊號和槽函式

QT學習---day2---訊號和槽函式

qt中的訊號和槽:(重點)
//需求:點選按鈕,關閉視窗;
4個主要內容:
connect(訊號的傳送者【按鈕】,傳送的訊號【點選的訊號】,訊號的接受者,處理的函式【槽函式】)
處理的過程:按鈕傳送一個“點選”的訊號,視窗接受一個“點選”的訊號,將訊號傳遞給“槽函式”。
//4 signals inherited from QAbstractButton,connect中的訊號查詢。
示例如下:
    //需求:點選btn 關閉視窗
    //引數1 訊號的傳送者  引數2 傳送的訊號(訊號地址)   引數3  訊號的接受者   引數4 處理的槽函式(槽函式的地址)
    //槽函式:public slot
     connect(btn,&QPushButton::clicked,this,&myWidget::close);


優點:鬆散耦合。左右事件本來不是相關的,利用connect關聯起來,將訊號傳送和訊號接收連線起來。
//****************************************************************************************


//****************************************************************************************
第二個專案:
自定義的訊號和槽
    qt的自定義訊號:
        返回值 void
        需要宣告,不需要實現
        可以有引數
    自定義槽函式:
        返回值void
        需要宣告,需要實現
        可以有引數
    觸發自定義的訊號
        emit

//teacher.h
#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject
{
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);

signals:
    //自定義的訊號需要寫到signal下:
    //返回的型別必須是void,
    //訊號只需要宣告,不需要實現,
    //訊號可以有引數,可以過載;
    void hungry();

public slots:
    //自定槽函式的地方;
    //高版本可以寫到public下,或者寫成全域性函式;(個人感覺寫到這裡更規範)。
};

#endif // TEACHER_H
//stude.h
#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class student : public QObject
{
    Q_OBJECT
public:
    explicit student(QObject *parent = nullptr);

signals:

public slots:
    //自定槽函式的地方;
    //高版本可以寫到public下,或者寫成全域性函式;(個人感覺寫到這裡更規範)。
    //槽函式需要宣告也需要實現;
    //槽函式也可以有函式,也可以過載;
    void treat();
};

#endif // STUDENT_H
//mywidget2.h
#ifndef MYWIDGET2_H
#define MYWIDGET2_H

#include <QWidget>
#include "teacher.h"
#include "student.h"

class mywidget2 : public QWidget
{
    Q_OBJECT

public:
    mywidget2(QWidget *parent = 0);
    ~mywidget2();

    //宣告兩個物件:
    //成員屬性可以儲存它;
    Teacher * zt;
    student * st;

    void classOver();
};

#endif // MYWIDGET2_H
//teacher.cpp
#include "teacher.h"

Teacher::Teacher(QObject *parent) : QObject(parent)
{

}

//student.cpp
#include "student.h"
#include <QDebug>
student::student(QObject *parent) : QObject(parent)
{

}

void student:: treat()
{
    qDebug()<<"請老師吃飯";

}

//mywidget2.cpp
#include "mywidget2.h"

//***************************************************************************************************************************************************

專案實踐:

//需求:建立兩個類:teacher 類 ,student 類
//下課後,老師teacher zt  會發出一個訊號---餓了  (發出訊號)----自定義訊號
//學生響應訊號student st  處理 訊號的槽函式,請客吃飯;

//mywidget2.cpp
#include "mywidget2.h"


//需求:建立兩個類:teacher 類 ,student 類
//下課後,老師teacher zt  會發出一個訊號---餓了  (發出訊號)----自定義訊號
//學生響應訊號student st  處理 訊號的槽函式,請客吃飯;

mywidget2::mywidget2(QWidget *parent)
    : QWidget(parent)
{
    zt = new Teacher(this);//將老師物件扔到childre表裡去了;
    st = new student(this);//




    //連線老師和學生:
    connect(zt,&Teacher::hungry,st,&student::treat);
    //需要時機觸發:
    classOver();
}

void mywidget2::classOver()
{
    //觸發老師餓了的訊號
    //老師餓了的訊號屬於自定義訊號,觸發自定義訊號的關鍵字 emit
    emit zt->hungry();
}



mywidget2::~mywidget2()
{

}
//main.cpp
#include "mywidget2.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    mywidget2 w;
    w.show();

    return a.exec();
}

//只用在原始檔mywidget2.cpp中更改即可

//********************************************************************************************
當自定義訊號和自定義槽函式發生過載時解決方法:
用函式指標明確呼叫的是有參還是無參的函式;
比如:將上述無參的自定義訊號和自定義槽改為有參的情況,則:

//student.h
#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class student : public QObject
{
    Q_OBJECT
public:
    explicit student(QObject *parent = nullptr);

signals:

public slots:
    //自定槽函式的地方;
    //高版本可以寫到public下,或者寫成全域性函式;(個人感覺寫到這裡更規範)。
    //槽函式需要宣告也需要實現;
    //槽函式也可以有函式,也可以過載;
    void treat();
    void treat(QString foodname);
};

#endif // STUDENT_H
//teacher .h
#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject
{
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);

signals:
    //自定義的訊號需要寫到signal下:
    //返回的型別必須是void,
    //訊號只需要宣告,不需要實現,
    //訊號可以有引數,可以過載;
    void hungry();

    void hungry(QString foodname);//訊號有參的情況

public slots:
    //自定槽函式的地方;
    //高版本可以寫到public下,或者寫成全域性函式;(個人感覺寫到這裡更規範)。
};

#endif // TEACHER_H
//mywidget2.h
#define MYWIDGET2_H

#include <QWidget>
#include "teacher.h"
#include "student.h"

class mywidget2 : public QWidget
{
    Q_OBJECT

public:
    mywidget2(QWidget *parent = 0);
    ~mywidget2();

    //宣告兩個物件:
    //成員屬性可以儲存它;
    Teacher * zt;
    student * st;

    void classOver();
};

#endif // MYWIDGET2_H
//student.cpp
#include "student.h"
#include <QDebug>
student::student(QObject *parent) : QObject(parent)
{

}

void student:: treat()
{
    qDebug()<<"請老師吃飯";

}

//槽函式有參的情況
void student::treat(QString foodname){

     qDebug()<<"請老師吃飯,老師要吃:"<<foodname;
}
//teacher.cpp
#include "teacher.h"

Teacher::Teacher(QObject *parent) : QObject(parent)
{

}
//mywidget2.cpp
#include "mywidget2.h"


//需求:建立兩個類:teacher 類 ,student 類
//下課後,老師teacher zt  會發出一個訊號---餓了  (發出訊號)----自定義訊號
//學生響應訊號student st  處理 訊號的槽函式,請客吃飯;

mywidget2::mywidget2(QWidget *parent)
    : QWidget(parent)
{
    zt = new Teacher(this);//將老師物件扔到childre表裡去了;
    st = new student(this);//




    //連線老師和學生:
    //connect(zt,&Teacher::hungry,st,&student::treat);

    //有參情況的連線:
    //函式指標指向函式地址;
    void (Teacher:: *teachersignal)(QString) = &Teacher::hungry;
    void (student::*studentslot)(QString) = &student::treat;//這兩句話是關鍵

    connect(zt,teachersignal,st,studentslot);

    //需要時機觸發:
    classOver();
}

void mywidget2::classOver()
{
    //觸發老師餓了的訊號
    //老師餓了的訊號屬於自定義訊號,觸發自定義訊號的關鍵字 emit

    emit zt->hungry();//觸發無參訊號

    emit zt->hungry("熱乾麵");//觸發有參訊號
}



mywidget2::~mywidget2()
{

}

//上述呼叫Connect時,有參函式的地址需要定義一個函式指標指向函式的地址,可以解決自定義訊號和自定義槽函式的過載問題;
//在呼叫emit觸發槽函式時,也要明確是呼叫的有參還是無參;

另附:
//QString 轉 char*
qDebug()<<"請老師吃飯,老師要吃:"<<foodname.toUtf8().data();
//1.先轉成Qbytearry型別、
//2.再轉為char*

//******************************
歸納:
當自定義訊號和槽 出現過載時候,原先寫法失效,因為執行的函式地址不明確;
解決方法:利用函式指標,來明確指向哪個函式的地址
QString 轉char*   toUtf8() 轉為 QBtyeArry型別,再利用data轉成char*;
//系統自帶的函式可能也會發生過載,此時也用上述方法進行解決。

//********************************************************************************************************
訊號和槽的擴充套件:
//用按鈕觸發訊號1,訊號1連線訊號2
//訊號2觸發槽函式;

//斷開訊號和槽:
disconnect();

//擴充套件:
//1.訊號可以連線訊號;
//2.訊號和槽可以斷開 disconnect
//3.一個訊號可以觸發多個槽函式;
//4.多個訊號可以連線同一個槽函式;
//5.訊號和槽的引數必須一一對應嗎?不一定
    //訊號的引數個數必須多餘槽函式的引數,但是型別必須一一對應。
    

 

參考:黑馬程式設計師培訓視訊