信号和槽
信号槽和机制
情景带人:
我们都知道鸿门宴,其中项羽想要杀刘邦,就在洪门设宴,并和手下兄弟约定只要项羽摔杯,就从进去绑了刘邦;
建立:信号和槽函数的关系使用connect
connect(信号的发起者,信号,接受者,操作);
案例:
widget的构造函数中:
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//设置窗口标题
this->setWindowTitle("信号");
//设置窗口大小
this->resize(800,600);
//创建一个按钮
QPushButton *btn1=new QPushButton("关闭",this);
//需求:单击btn1 关闭主窗口
//信号的发起者btn1 发出信号 主窗口this 关闭(槽函数)
connect(btn1, &QPushButton::clicked, this, &QWidget::close);
//lambda表达式
QPushButton *btn2 =new QPushButton("戳我呀",this);
btn2->move(400,300);
connect(btn2, &QPushButton::clicked, [=](){
//获取按钮上的文本
QString text = btn2->text();
qDebug()<<text <<endl;
//设置按钮的文本
btn2->setText("戳你咋地?");
} );
}
运行结果:
自定义信号和槽(了解)
老师—>饿了信号 学生—>请老师吃饭
设计两个类:老师类 学生类
注意:
1、定义信号的规则:在signals下方返回值类型为void 只需声明 不用实现 可以有参数 可以重载
2、定义槽函数的规则:public slots:返回值类型为void 需要声明 需要实现 可以有参数 可以重载
3、用户可以使用emit 发出信号
emit tea->hungry();
案例:
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = 0);
signals:
public slots:
//返回值类型为void 需要声明 需要实现 可以有参数 可以重载
void treat();
void treat(QString foodName);
};
#endif // STUDENT_H
student.cpp
#include "student.h"
#include<QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug()<<"请老师吃饭了"<<endl;
}
void Student::treat(QString foodName)
{
qDebug()<<"请老师吃饭了"<<foodName<<endl;
}
teacher.h
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
#include<QString>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = 0);
signals://自定义信号函数
//定义信号的规则:返回值类型void 只需声明 不用实现 可以有参数 可以重载
void hungry();
void hungry(QString foodName);
public slots://自定义槽函数
};
#endif // TEACHER_H
teacher.cpp
#include "teacher.h"
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
widget构造函数:
#include "widget.h"
#include"teacher.h"
#include"student.h"
#include<QPushButton>
#define N 0
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//设置主窗口大小
this->resize(800,600);
//实例化一个老师
Teacher *tea = new Teacher(this);
//实例化一个学生
Student *stu = new Student(this);
#if N
//connect建立老师和学生的关系
void (Teacher:: *p1)() = &Teacher::hungry;
void (Student:: *p2)() = &Student::treat;
connect(tea,p1, stu, p2);
#else
//报错的原因:hungry信号被重载了
//通过函数指针 明确那个信号
void (Teacher:: *p1)(QString foodName) = &Teacher::hungry;
void (Student:: *p2)(QString foodName) = &Student::treat;
connect(tea,p1, stu, p2);
#endif
//下课了 老师饿了
QPushButton *btn = new QPushButton("下课", this);
connect(btn,&QPushButton::clicked,[=](){
#if N
//下课函数:让老师发出饿的信号
emit tea->hungry();
#else
//下课函数:让老师发出饿的信号
emit tea->hungry("锅包肉");
#endif
});
}
Widget::~Widget()
{
}
总结:
1、一个信号可以和多个槽相连
如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的。
2、多个信号可以连接到一个槽
只要任意一个信号发出,这个槽就会被调用。
3、一个信号可以连接到另外的一个信号
当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。
4、槽可以被取消链接
这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽。
5、Qt4版本的信号槽写法
connect(tea,SIGNAL(hungry()), stu, SLOT(treat()));
6、Qt5版本的信号槽写法
connect(tea, &Teacher::hungry, stu, &Student::treat);
综合案例(窗口切换)
创建一个窗口类:
类名为:swidget
swidget.h
#ifndef SWIDGET_H
#define SWIDGET_H
#include <QWidget>
class SWidget : public QWidget
{
Q_OBJECT
public:
explicit SWidget(QWidget *parent = 0);
signals:
void back();//回退信号
public slots:
};
#endif // SWIDGET_H
swidget.cpp
#include "swidget.h"
#include<QPushButton>
SWidget::SWidget(QWidget *parent) : QWidget(parent)
{
//设置查询窗口的大小
this->resize(800,600);
this->setWindowTitle("查询窗口");
//定义一个回退按钮
QPushButton *btn = new QPushButton("back",this);
//当按下back 就发出一个back信号
connect(btn,&QPushButton::clicked,[=](){
emit this->back();
});
}
widget.cpp
#include "widget.h"
#include <QPushButton>
#include"swidget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->resize(800,600);
this->setWindowTitle("登录");
//定义一个查询窗口
SWidget *s = new SWidget();
//创建一个下一页的按钮
QPushButton *btn = new QPushButton("下一页",this);
connect(btn,&QPushButton::clicked,[=](){
//当前窗口隐藏
this->hide();
//查询窗口显示
s->show();
});
//监测查询窗口s的回退信号
connect(s,&SWidget::back,[=](){
//隐藏查询窗口
s->hide();
//显示当前窗口
this->show();
});
}
Widget::~Widget()
{
}
运行结果: