目录
举一个简单的例子,前面创建了一个QPushButton之后,界面上确实生成了一个按钮,但是点击这个按钮没有任何反应,这是因为还没有给按钮加上一系列处理方法,Qt可以通过信号与槽机制实现让一个按钮点击后产生后续的动作,这个动作的流程如下:
按钮(信号的发送者)->点击(发送的具体信号)->窗口(信号的接受者)->关闭(信号的处理)
1.connect()函数
上述的流程在Qt中通过connect()函数可以连接起来
//创建按钮对象
QPushButton *btn = new QPushButton("BUTTON",this);
//信号与槽
connect(btn,&QPushButton::clicked,this,&Widget::close);
2.自定义信号和槽
设计一个功能,老师类和学生类,老师类中触发信号,学生类槽函数接受信号,老师饿了,学生就请吃饭。
teacher.h
- 自定义信号写到signals下
- 返回值是void,只需要声明,不需要实现
- 可以有参数,可以重载
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
//自定义信号写到signals下
//返回值是void,只需要声明,不需要实现
//可以有参数,可以重载
void hungry();
};
#endif // TEACHER_H
teacher.cpp
不需要实现信号函数。
#include "teacher.h"
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
student.h
- 早期Qt有一个 public slot:专门写槽函数,高版本的直接写到public:中,或者全局函数中
- 槽函数:需要声明,也需要在.cpp中实现
- 可以有参数,可以发生重载
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
//早期Qt有一个 public slot:专门写槽函数,高版本的直接写到public:中,或者全局函数中
//槽函数:需要声明,也需要在.cpp中实现
//可以有参数,可以发生重载
void treat();
signals:
};
#endif // STUDENT_H
student.cpp
需要实现槽函数
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug()<<"请老师吃饭";
}
widget.h
老师类对象和学生类对象以及触发下课的函数要在private中声明。
#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 *zy;
Student *st;
void classIsOver();
};
#endif // WIDGET_H
widget.cpp
先connect连接,再调用触发函数,顺序不能错
emit手动触发信号
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建老师对象
this->zy=new Teacher(this);
//创建学生对象
this->st=new Student(this);
//老师饿了,学生就请吃饭
connect(zy,&Teacher::hungry,st,&Student::treat);
//调用下课函数,先连接,后调用,有顺序要求
classIsOver();
}
void Widget::classIsOver()
{
//下课函数,触发老师饿了的信号
//emit手动触发信号
emit zy->hungry();
}
Widget::~Widget()
{
delete ui;
}
3.当信号与槽函数发生重载
当出现函数重载
void hungry();
//teacher.h带参数重载
void hungry(QString foodName);
void treat();
//student.h带参数重载
void treat(QString foodName);
//student.cpp中实现
void Student::treat()
{
qDebug()<<"请老师吃饭";
}
void Student::treat(QString foodName)
{
qDebug()<<"请老师吃饭,吃的饭是:"<<foodName.toUtf8().data();
}
//widget.cpp中调用有参函数
void Widget::classIsOver()
{
emit zy->hungry("宫保鸡丁");
}
不能再使用:
connect(zy,&Teacher::hungry,st,&Student::treat);
需要使用函数指针:
//连接带参数的信号和槽
//函数指针->函数地址
void(Teacher::*teacherSignal)(QString)=&Teacher::hungry;
void(Student::*studentSlot)(QString)=&Student::treat;
connect(zy,teacherSignal,st,studentSlot);
4.QString和char *转换
QString输出的汉子自带双引号,char*不带,QString转char*分两步,先转成QBtyeArray,.toutf8()
再转char* .data()
//QString转char *,可以使汉子不加双引号
//先转成QBtyeArray,.toutf8()
//再转char* .data()
qDebug()<<"请老师吃饭,吃的饭是:"<<foodName.toUtf8().data();
5.信号传递信号
新增一个按钮,使用按钮去触发老师饿了的信号,而不是用classIsOver去调用老师饿了
//点击按钮后再触发下课,信号传递信号
QPushButton *btn=new QPushButton("Button",this);
//重置窗口大小
resize(600,400);
//第一种方法
//connect(btn,&QPushButton::clicked,this,&Widget::classIsOver);
//第二种方法,信号连接信号
void(Teacher::*teacherSignal2)(void)=&Teacher::hungry;
void(Student::*studentSlot2)(void)=&Student::treat;
connect(zy,teacherSignal2,st,studentSlot2);
connect(btn,&QPushButton::clicked,zy,teacherSignal2);
//断开信号
//disconnect(zy,teacherSignal2,st,studentSlot2);
6.信号与槽总结
1.信号可以连接信号;
2.一个信号可以连接多个槽函数;
3.多个信号可以连接同一个槽函数;
4.信号与槽的参数 必须类型一一对应;
5.信号与槽的参数个数,信号参数个数可以多于槽的参数个数。
7.Qt4信号与槽
参数更直观,但类型不做检测
connect(zy,SIGNAL(hungry()),st,SLOT(treat()));