—— 均为自学笔记,如有错误请指正
第一节 信号和槽
一、点击按钮关闭窗口
1. 介绍 连接函数connect()
按钮——点击——窗口——关闭窗口
connect(信号的发送者,发送的具体信号,信号的接收者,信号的处理(槽))
- 槽就是信号处理的槽函数
- 信号槽的优点:松散耦合(信号发送端和接收端本身是没有关联 的,通过connect连接,将两端耦合在一起)
2. 使用 connect()
connect(发送者(指针/地址),发送的信号(函数的地址),接收者(指针/地址),处理的槽(函数地址))
connect(myBtn,&QPushButton::clicked,this,&QWidget::close); //父类
// or
connect(myBtn,&MyPushButton::clicked,this,&myWidget::close);//子类
注: 对于函数来说,函数名可以隐式转换为函数指针,因此&写与不写一致。
3. 信号Signals :
- void clicked(bool checked = false) 点击
- void pressed() 摁下瞬间
- void released() 释放瞬间
- void toggled(bool checked) 根据bool切换状态 //toggled:切换
4. 槽函数(Qt助手可查看 QWidget → Public Slots)
二、创建自定义的信号和槽
案例需求:
//Teacher 类 老师类
//Student 类 学生类
//下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
分析:发送者:Teacher ,信号 :饿了,接收者:学生,处理槽函数:请吃饭
1. 新建类
当新建的类不属于任何一个控件时,可以选择最高级别的类,如下图:
2. 自定义信号
① 位置:创建好类以后在 类.h 文件中的signals 下就是写自定义信号的位置,如下图:
② 写法:
- 没有返回值,即返回值是void ,在信号里面只需要声明,不需要实现
- 可以有参数,可以无参数,即可以重载
3. 自定义槽函数
① 位置:写在 接收类.h 文件的 public下
注:早期版本必须写在public slots下,高级版本可以写在public或者全局下
② 写法:
- 返回值 void,需要声明,也需要实现
- 可以有参数,可以发生重载
4. 声明对象
位置 :在 widget.h 中声明对象
Teacher * zt;
Student * st;
5. 创建对象
位置 : 在 widget.cpp 中创建对象
//创建一个老师对象
this->zt = new Teacher(this);
//创建一个学生对象
this->st = new Student(this);
6. 连接
位置 : .cpp中 创建完对象后
写法:connect();
7. 方法(条件)
注: 下课后这个 条件(方法)
① 写法:需声明,需实现。
② 声明位置: widget.h下
void classIsOver();
③ 实现位置: widget.cpp下
void Widget::classIsOver()
{
//下课函数,调用后,触发老师饿了的信号
emit zt->hungry();
}
注: 调用 信号 (发送者那个信号)
触发自定义的信号:emit 自定义信号
④ 调用方法:widget.cpp下
//调用下课函数
classIsOver();
注: 注意调用方法和信号的代码顺序
三、自定义的信号和槽 出现重载
注:成员函数和指向该成员的指针之间不存在自动转换规则,所以必须显式地使用取址运算符(&)
- 需要利用函数指针 明确指向函数的地址
//声明成员函数的函数地址时,需在指针前边加成员函数的作用域
void( Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
void(Student:: *stuentSlot)(QString) = &Student::treat;
connect(zt,teacherSignal,st,stuentSlot);
classIsOver();
- QString 格式 转成 char*
//QString型打印出来会加"",转换一下即可取消
//QString -> char* 转换:
//先转成QByteArray : 通过 .toUtf8()
//转成char* : 通过 .data()
qDebug()<< "eat _this" << foodName.toUtf8().data() ;
四、 信号连接与断开
1. 信号连接信号 信号连接槽 断开信号
//点击按钮 触发下课事件
// 信号连接槽
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);
//断开信号
disconnect(zt,teacherSignal2,st,studentSlot2);
2. 信号连接拓展:
- 信号可以连接信号
- 一个信号可以连接多个槽函数
- 多个信号可以连接同一个槽函数
- 信号和槽函数的参数类型必须一一对应
- 信号和槽的参数个数 是不是要一致? 信号的参数个数可以多于槽函数的参数个数(但是对应的类型需要一致)
3. Qt4版本以前的信号和槽连接方式
//Qt4 连接无参版本
connect(zt,SIGNAL(hungry()),st,SLOT(treat()));
//优点: 参数直观。缺点: 类型不做检测。
// 错误例子:connect(zt,SIGNAL(hungry()),st,SLOT(treat(QString)));
Qt4版本 底层:SIGNAL("hungry") SLOT("treat") 字符串直接找函数
五、Lambada表达式(C++11新特性)
1. 简介
用于定义并创建匿名的函数对象
2. 基本构成
/*
[函数对象参数](操作符重载函数参数)mutable->返回值
{
函数体
}
*/
[capture](parameters)mutable->return-type
{
statement
}
//将btn按钮改名 最后的 ();是函数调用,不调用无法成功。
[=]()
{
btn->setText("aaa");
}();
3. 配置
早期版本需要在.pro中加入 CONFIG += c++11
4. 函数对象参数形式 [ ]
空:没有使用任何函数对象参数
= :函数体内可以使用Lambda所在作用范围内所有可见的局部变量(值传递方式)
&:函数体内可以使用Lambda所在作用范围内所有可见的局部变量(引用传递方式)
this:函数体内可以使用Lambda所在类中的成员变量
a :将a按值进行传递。修改需加mutable修饰符
&a:将a按引用进行传递
a,&b:将a按值进行传递,b按引用进行传递
=,&a,&b:除了a和b按引用进行传递外,其他参数都按值进行传递
&,a,b:除a,b按值传递,其他参数都按引用进行传递
5. 操作符重载函数参数 ( )
标识重载 ( ) 操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(a,b)和按引用(&a,&b)进行传递。
6. 可修改标示符
mutable声明,这部分可以省略。
按值传递函数对象参数时,加上mutable修饰符( 在 [ ] ( ) 这里添加{ } )后,可以修改按值传递进来的拷贝(只能是拷贝,不能是本身)。
QPushButton * myBtn = new QPushBtoon(this);
QPushButton * myBtn2 = new QPushBtoon(this);
myBtn->move(100,100);
int m = 10;
connect(myBtn,&QPushButton::clicked,this,[m]()mutable{m = 100+10;qDebug()<<m;});
connect(myBtn2,&QPushButton::clicked,this,[=](){qDebug()<<m;});
qDebug()<<m;
7. 函数返回值
->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方时,这部分可以省略。
int ret = []()->int{return 1000;}(); //此处的()是调用函数,必须得有
qDebug() << "ret = "<< ret;
8. 函数体 { }
标识函数的实现,这部分不能省略,但函数体可以为空。
9. 使用
- 点击按钮关闭窗口
- connect() 第三个参数是this时,可以省略
QPushButton * btn2 = new QPushButton;
btn2->setText("close");
btn2->move(100,0);
btn2->setParent(this);
// 下面第三个参数是this时可以省略
connect(btn2,&QPushButton::clicked,this,[=]()
{
this->close();
//此处可以直接调用槽函数
emit zt->hungry("foodName");
});
10. Lambda表达式最常用: [=](){}
六、作业
1. 普通版:
创建两个按钮:一个open,另一个close,点击open,弹出另一个窗口,点击close关闭所打开的窗口
2. 升级版:
一个按钮,显示open,点击打开窗口,并且显示为close,点击close关闭窗口