一、信号槽
信号:signal (比如click)
槽: slot
实现wedget窗口的关闭
(例子实现接着Qt学习笔记一的过程)
点击myBtn实现wedget窗口关闭
参数1:信号的发送者
参数2:发送的信号(函数地址)
参数3: 信号的接收者
参数4: 处理的槽函数
//需求:点击我的按钮 关闭窗口 //参数1:信号的发送者 参数2:发送的信号(函数地址) 参数3: 信号的接收者 参数4: 处理的槽函数 connect(myBtn,&QPushButton::clicked,this,&QWidget::close); // connect(myBtn,&MyPushButton::clicked,this,&Widget::close);//因为继承关系,也可以直接通过这种调用信号和槽函数
过程:
要找按钮的信号,可以使用帮助文档搜索QPushButton然后找到signal
需要找到wedget的槽,可以帮助文档搜QWedget然后找到slot
自动补全时,那种函数名前带有波纹图样的就是信号
总结
二、自定义信号和槽
(新建一个工程,过程中选择cmake,初始为widget) 创建工程结束后如下图所示
首先创建Teacher类,由于它不属于任何控件,因此选择QObject作为基类,这样如果setParent,就可以实现自动释放
案例:
Teacher类 老师类
Student类 学生类
下课后,老师会触发一个型号,饿了,学生响应信号,请客吃饭
创建Teacher类
teacher.h
在signal
下,添加一个hungry
(饥饿)信号
#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类
student.h
在pulic slots
下面定义一个槽函数treat
(请客)
#ifndef STUDENT_H #define STUDENT_H #include <QObject> class Student : public QObject { Q_OBJECT public: explicit Student(QObject *parent = nullptr); signals: public slots: //早期Qt版本 必须要写到public slots,高级版本可以写到public 或者全局下 //返回值void ,需要声明,也需要实现 //可以有参数,可以发生重载 void treat(); }; #endif // STUDENT_H
student.cpp
student槽函数的实现
#include "student.h" #include<QDebug> Student::Student(QObject *parent) : QObject{parent} { } void Student::treat() { qDebug()<<"Invite the teacher to dinner"; }
信号连接槽函数与触发信号
在widget.h中定义了 Student对象,Teacher对象,以及 下课的函数
#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* zt; Student* st; void classIsOver(); }; #endif // WIDGET_H
widget.cpp
创建老师、学生对象 ,连接信号(饥饿)与槽函数(请客)
调用下课 函数,触发老师饥饿信号
#include "widget.h" #include "./ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //创建一个老师对象 this->zt=new Teacher(this); //创建一个学生对象 this->st=new Student(this); //老师饿了 学生请客的连接 connect(zt,&Teacher::hungry,st,&Student::treat); //调用下课函数 classIsOver(); } Widget::~Widget() { delete ui; } void Widget::classIsOver() { //下课函数,调用 出发老师饿了信号 emit zt->hungry();//emit表示发射信号的意思 }
总结
三、自定义的信号和槽发生重载
重载信号和槽函数
比如Teacher
类中对信号发生 重载
一个是无参,一个是有参
void hungry(); void hungry(QString foodName);
对Student
类对槽函数发生重载
void treat(); void treat(QString foodName);
对重载的信号和槽进行连接
由于直接用函数名会产生二义性,因此要定义函数指针,指定是有参的那个
然后讲 信号和槽函数 的函数指针 传入即可
//连接带参数的 信号和槽 void(Teacher::*teacherSignal)(QString) = &Teacher::hungry;//定义一个函数指针,指向有参的 void(Student::*studentSlot)(QString) = &Student::treat; // connect(zt,&Teacher::hungry,st,&Student::treat);如果直接传这个会产生二义性,因为重载了一个有参的。如果没有重载,可以这么用 connect(zt,teacherSignal,st,studentSlot);
补充
另外在void Student::treat(QString foodName)
实现过程中,发现chicken
带了引号
如果不想用引号,可以 .toUtf8().data()
void Student::treat(QString foodName) { //QString 转成 char* 先转成QByteArray(.toUtf8()) 再转char* (.data()) qDebug()<<"Invite the teacher to eat "<<foodName.toUtf8().data(); }
总结
四、信号连接信号
点击按钮->触发下课->触发老师饿了->学生请客
点击按钮触发下课,触发老师饿,触发学生请客
//点击一个 下课按钮,再触发下课 QPushButton *btn = new QPushButton("classOver",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(zt,teacherSignal2,st,studentSlot2); //信号连接信号 connect(btn,&QPushButton::clicked,zt,teacherSignal2); //断开信号(参数是和connect一样的) disconnect(zt,teacherSignal2,st,studentSlot2);
总结
五、信号槽连接的一些注意点和Qt4版本信号槽连接
1.信号是可以连接信号
2.一个信号 可以连接 多个槽函数
3.多个信号 可以连接 同一个槽函数
4.信号和槽函数的参数 必须类型一一对应
5.信号和槽的参数个数是不是要一致? 信号参数的个数 可以多余槽参数个数。 反之不行
另外Qt4的信号槽连接就不介绍了,它的优点:参数直观。 缺点:类型不做检测
六、信号槽连接中使用lambda表达式
//lambda表达式作为信号槽连接的槽函数 (mutable关键字,用于修饰值传递变量,使得值传递拷贝的结果可以修改) QPushButton* btn2=new QPushButton("second btn",this); btn2->move(100,100); int m=100; connect(btn2,&QPushButton::clicked,this,[m]()mutable{m=m+10;qDebug()<<m;}); //lambda表达式,如果返回int, 返回值用->int。直接加括号可以调用 int ret=[m]()->int{return m;}(); qDebug()<<"ret = "<<ret; //利用lambda表示,实现点击按钮,关闭窗口 QPushButton *btn3=new QPushButton("close widget",this); btn3->move(300,100); connect(btn3,&QPushButton::clicked,this,[this](){ emit zt->hungry("chicken"); this->close(); }); //如果第3个参数是this,使用lambda表达式,可以省略第三个参数,直接输入lambda表达式就行 connect(btn3,&QPushButton::clicked,[this](){ emit zt->hungry("chicken"); this->close(); });
七、总结
八、练习
设置一个按钮,点击open,可以显示一个窗口,并按钮文本变成close。
点击close,关闭刚才打开的窗口,并按钮文本变成open
和之前一样的方式创建工程
widget.cpp
#include "widget.h" #include "./ui_widget.h" #include<QPushButton> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); QPushButton *btn1=new QPushButton("open",this); this->resize(600,600); QWidget *subW=new QWidget; connect(btn1,&QPushButton::clicked,this,[=,flag=true]()mutable{ if(flag==true){ btn1->setText("close"); flag=false; subW->show(); } else if(flag==false){ btn1->setText("open"); flag=true; subW->close(); } }); } Widget::~Widget() { delete ui; }
九、其他
QT智能提示可能有些不舒服,提示出来慢
于是设置一下
工具-》选项-》文本编辑器-》Completion
中的Timeout in ms(提示延迟):可以设置小一点(看个人习惯)
Character threshold(字符阈值):输入超过阈值个字符就可以代码提示