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.訊號和槽的引數必須一一對應嗎?不一定
//訊號的引數個數必須多餘槽函式的引數,但是型別必須一一對應。
參考:黑馬程式設計師培訓視訊