一、定义
信号与槽(Signal & Slot)是 Qt 编程的基础,也是 Qt 的一大创新。因为有了信号与槽的编程机制,在 Qt 中处理界面各个组件的交互操作时变得更加直观和简单。
信号(Signal)就是在特定情况下被发射的事件,例如 PushButton 最常见的信号就是鼠标单击时发射的 clicked() 信号,一个 ComboBox 最常见的信号是选择的列表项变化时发射的CurrentIndexChanged() 信号。
GUI 程序设计的主要内容就是对界面上各组件的信号的响应,只需要知道什么情况下发射哪些信号,合理地去响应和处理这些信号就可以了。
槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的 C++函数是一样的,可以定义在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。
信号与槽关联是用 QObject::connect() 函数实现的:
connect(btn,&QPushButton::clicked,this,&QWidget::close);
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); // 第一个按钮 QPushButton * btn=new QPushButton; //show以顶层方式弹出窗口坤健 // btn->show(); //让队形依赖于widget窗口 btn->setParent(this); //显示文本 btn->setText("关闭按钮"); // 创建第二个按钮,按照按钮的大小创建窗口 QPushButton * btn2=new QPushButton("第二个按钮",this); btn2->move(100,100); // 重置窗口大小 resize(600,400); // 设置固定窗口大小 setFixedSize(600,400); // 设置窗口标题 setWindowTitle("第一个窗口"); //需求,点击关闭按钮,关闭窗口 //参数1:信号发送者 参数2:发送的信号 参数3:信号接受者 参数4:处理的槽函数 connect(btn,&QPushButton::clicked,this,&QWidget::close); }
二、自定义信号和槽
//Teacher类 老师类 //Student类 学生类 //下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
依次创建teacher和student类
1、自定义信号
teacher.h
#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} { }
2、自定义槽
student.h
#ifndef STUDENT_H #define STUDENT_H #include <QObject> class Student : public QObject { Q_OBJECT public: explicit Student(QObject *parent = nullptr); //早期Qt版本,必须要写到public slots,高级本本可以写到public或者全局下 //返回值void,需要申明,也需要实现 //可以有参数,可以发生重载 void treat(); signals: }; #endif // STUDENT_H
student.cpp
#include "student.h" #include<QDebug> Student::Student(QObject *parent) : QObject{parent} { } void Student::treat(){ qDebug()<<"请老师吃饭"; }
3、关联信号和槽并发送信息
widget.h
#include "widget.h" #include "ui_widget.h" //Teacher类 老师类 //Student类 学生类 //下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭 Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //创建一个老师对象 this->th=new Teacher(this); //创建一个学生对象 this->st=new Student(this); //老师饿了,学生请客的连接 connect(th,&Teacher::hungry,st,&Student::treat); //调用下课函数,触发信号 classIsOver(); } void Widget::classIsOver(){ //下课函数,调用后,触发老师饿了的信号 emit th->hungry(); } Widget::~Widget() { delete ui; }
三、带参数信号和槽
teach.h
#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(); void hungry(QString foodName); }; #endif // TEACHER_H
student.h
#ifndef STUDENT_H #define STUDENT_H #include <QObject> class Student : public QObject { Q_OBJECT public: explicit Student(QObject *parent = nullptr); //早期Qt版本,必须要写到public slots,高级本本可以写到public或者全局下 //返回值void,需要申明,也需要实现 //可以有参数,可以发生重载 void treat(); void treat(QString foodName); signals: }; #endif // STUDENT_H
student.cpp
#include "student.h" #include<QDebug> Student::Student(QObject *parent) : QObject{parent} { } void Student::treat(){ qDebug()<<"请老师吃饭"; } void Student::treat(QString foodName){ //QString转换为char * qDebug()<<"请老师吃饭,老师要吃"<<foodName.toUtf8().data(); }
widget.cpp
#include "widget.h" #include "ui_widget.h" #include<QPushButton> //Teacher类 老师类 //Student类 学生类 //下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭 Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //创建一个老师对象 this->th=new Teacher(this); //创建一个学生对象 this->st=new Student(this); //老师饿了,学生请客的连接 // connect(th,&Teacher::hungry,st,&Student::treat); //调用下课函数,触发信号 // classIsOver(); //连接带参数的信号和槽 //指针->地址 //函数指针->函数地址 void(Teacher ::*teacherSignal)(QString)=&Teacher::hungry; void(Student::*studentSlot)(QString)=&Student::treat; connect(th,teacherSignal,st,studentSlot); // classIsOver(); //点击一个下课按钮,触发下课 QPushButton * btn=new QPushButton("下课",this); //重置窗口大小 this->resize(600,400); //点击按钮,触发下课 // connect(btn,&QPushButton::clicked,this,&Widget::classIsOver); void(Teacher ::*teacherSignal2)(void)=&Teacher::hungry; void(Student::*studentSlot2)(void)=&Student::treat; connect(th,teacherSignal2,st,studentSlot2); //信号连接信号 connect(btn,&QPushButton::clicked,th,teacherSignal2); //断开信号 disconnect(th,teacherSignal2,st,studentSlot2); //扩展 //1、信号是可以连接信号; //2、一个信号可以连接多个槽函数; //3、多个信号可以连接同一个槽函数; //4、信号和槽函数的参数,必须类型一一对应; //5、信号的参数个数可以多余槽函数的参数个数。 //Qt4版本以前的信号和槽连接方式 //利用Qt4信号和槽,连接无参版本 connect(th,SIGNAL(hungry()),st,SLOT(treat())); //优点参数直观,缺点类型不做检测L } void Widget::classIsOver(){ //下课函数,调用后,触发老师饿了的信号 emit th->hungry(); emit th->hungry("宫保鸡丁"); } Widget::~Widget() { delete ui; }
1、信号是可以连接信号;
2、一个信号可以连接多个槽函数;
3、多个信号可以连接同一个槽函数;
4、信号和槽函数的参数,必须类型一一对应;
5、信号的参数个数可以多余槽函数的参数个数。
使用lamdba
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //创建一个老师对象 this->th=new Teacher(this); //创建一个学生对象 this->st=new Student(this); //老师饿了,学生请客的连接 // connect(th,&Teacher::hungry,st,&Student::treat); //调用下课函数,触发信号 // classIsOver(); //连接带参数的信号和槽 //指针->地址 //函数指针->函数地址 void(Teacher ::*teacherSignal)(QString)=&Teacher::hungry; void(Student::*studentSlot)(QString)=&Student::treat; connect(th,teacherSignal,st,studentSlot); // classIsOver(); //点击一个下课按钮,触发下课 QPushButton * btn=new QPushButton("下课",this); //重置窗口大小 this->resize(600,400); //点击按钮,触发下课 // connect(btn,&QPushButton::clicked,this,&Widget::classIsOver); void(Teacher ::*teacherSignal2)(void)=&Teacher::hungry; void(Student::*studentSlot2)(void)=&Student::treat; connect(th,teacherSignal2,st,studentSlot2); //信号连接信号 connect(btn,&QPushButton::clicked,th,teacherSignal2); //断开信号 disconnect(th,teacherSignal2,st,studentSlot2); //扩展 //1、信号是可以连接信号; //2、一个信号可以连接多个槽函数; //3、多个信号可以连接同一个槽函数; //4、信号和槽函数的参数,必须类型一一对应; //5、信号的参数个数可以多余槽函数的参数个数。 //Qt4版本以前的信号和槽连接方式 //利用Qt4信号和槽,连接无参版本 connect(th,SIGNAL(hungry()),st,SLOT(treat())); //优点参数直观,缺点类型不做检测 //lambda //值传递 [=](){ btn->setText("AAA"); }(); //引用传递 [&](){ btn->setText("BBB"); }(); int ret=[]()->int{return 1000;}(); qDebug()<<"ret="<<ret; //利用lambda表达式,实现点击按钮,关闭窗口 QPushButton *btn2=new QPushButton; btn2->setText("关闭"); btn2->move(100,0); btn2->setParent(this); connect(btn2,&QPushButton::clicked,this,[=](){ emit th->hungry("lalala"); }); }