信号和槽机制
QT提供了信号和槽机制用于完成界面操作的响应,信号和槽是用来完成任意两个QT对象之间的通信机制。
信号和槽机制的连接方式
信号和槽函数之间需要通过connect函数进行连接 Qt中connect
函数的基本语法:
cpp
connect(发送者, 发送的信号, 接收者, 槽函数);
发送者
:发射信号的对象。发送的信号
:信号函数的地址接收者
:具有槽函数来处理信号的对象。槽函数
:指定槽函数地址
示例: 创建一个按钮,点击按钮关闭窗口
首先在主窗口构造函数中实现代码如下:
cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//新建按钮
QPushButton* btn =new QPushButton("按钮",this);
//连接信号和槽clicked是QT库提供的,close是QWidget中的槽函数都是库提供的,QMainWindow继承了QWidget,所以也能直接用
connect(btn,&QPushButton::clicked,this,&QMainWindow::close);
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果
QT自定义信号和槽
通过自定义信号和槽,可以在应用程序中实现自己的事件处理机制。
自定义信号
- 自定义的信号需要写的类中signal访问限定符下
- 返回值是void
- 自定义的信号只需要声明不需要实现。
- 自定义的信号可以有参数,即支持重载
- 触发信号需要使用关键字emit
自定义槽函数
- 自定义的槽函数需要声明且需要实现
- 可以写到public,或者public slot访问限定符下,或者写为全局函数。(一般建议写到public slot下,新老版本的qt都支持,写到piblic下只有新版本支持)
- 槽函数也可以有参数,也支持重载,信号和槽函数的参数类型必须一一对应
- 信号的参数可以多于槽函数的参数个数
示例
比如实现一个场景,老师下课后触发饿了的信号,学生接收信号请老师吃饭
在teacher类中声明信号
cpp
//teacher.h
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
//自定义信号只需要声明 不需要实现
//返回值是void
void signa();
};
#endif // TEACHER_H
再student类中声明槽函数
cpp
//satudent.h
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
//自定义槽函数,需要声明且实现
void slot();
signals:
};
#endif // STUDENT_H
实现Student中slot函数
cpp
//student.cpp
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent)
: QObject{parent}
{}
void Student::slot()
{
qDebug() << "Invite the teacher to dinner";//请老师吃饭
}
在窗口类中声明一个下课后的函数
cpp
//MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "teacher.h"
#include "student.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void trigger();//下课后触发信号
private:
Ui::MainWindow *ui;
Teacher* _t1;
Student* _s1;
};
#endif // MAINWINDOW_H
实现下课后,触发老师饿了的信号,触发之前连接信号和槽函数
cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
_t1 = new Teacher(this);
_s1 = new Student(this);
//连接信号和槽
//connect参数1 信号发送者,参数2 发送的信号
// 参数3 信号的接收者 参数4 槽函数
connect(_t1,&Teacher::signa,_s1,&Student::slot);
trigger();
}
//实现下课后触发老师饿了的信号
void MainWindow::trigger()
{
//触发信号关键字
emit _t1->signa();
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:
成功的请老师吃饭了(吃赛博晚饭)。成功的连接到了自定义的信号和槽
对上面进行改进,添加一个按钮,点击按钮,触发信号
cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
_t1 = new Teacher();
_s1 = new Student();
//添加按钮
QPushButton* _btn = new QPushButton("按钮",this);
resize(600,400);
//连接信号和槽
//connect参数1 信号发送者,参数2 发送的信号
// 参数3 信号的接收者 参数4 槽函数
connect(_t1,&Teacher::signa,_s1,&Student::slot);
//点击按钮,触发信号
connect(_btn,&QPushButton::clicked,this,&MainWindow::trigger);
}
void MainWindow::trigger()
{
//触发信号关键字
emit _t1->signa();
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果
自定义信号和槽函数发生重载
connewct连接信号和槽函数时,参数需要传函数得地址,当发生重载时需要利用函数指针明确函数的地址
Teacher类中声明信号
cpp
void signa();
void signa(QString str);
两个singa构成重载
在Student类中声明并实现槽函数
cpp
//student.h
void slot();
void slot(QString str);
cpp
//student.cpp
void Student::slot()
{
qDebug() << "Invite the teacher to dinner";
}
void Student::slot(QString str)
{
qDebug() << "Invite the teacher to dinner,eat:" << str;
}
窗口类中实现功能
cpp
//信号和槽函数发生重载时,需要用函数指确定函数的地址
void (Teacher::*signaadder1)()= &Teacher::signa;//无参信号地址
void (Teacher::*signaadder2)(QString)= &Teacher::signa;//有参信号地址
void (Student::*slotadder1)() = &Student::slot;//无参槽函数地址
void (Student::*slotadder2)(QString) = &Student::slot;//有参槽函数地址
//连接信号和槽函数
connect(_t1,signaadder2,_s1,slotadder2);
//通过按钮点击触发信号
connect(_btn,&QPushButton::clicked,this,&MainWindow::trigger);
运行结果:
成功调用了有参版本的槽函数。