自定义信号要写到signals下,只需要声明,不需要重载,返回值为void。
在早期版本,需要将槽函数写在public slots下,而在5.4之后,可以将槽函数写在public下或者写在全局下。需要声明与实现,返回void。
考虑下面的应用场景:下课后,同学感到饥饿,老师请客吃饭。
对于这个问题需要实现Student与Teacher两个实体类,均继承QObject基类以便析构。Student类有hungry这个信号,Teacher类有treat这个槽函数。Widget类中含有Student与Teacher两个类型的成员变量,含有classOver()成员方法。调用classOver()方法激活hungry信号,从而触发treat槽函数。
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
void hungry(); //hungry信号的声明,无需实现
};
#endif // STUDENT_H
student.cpp
#include "student.h"
Student::Student(QObject *parent)
: QObject{parent}
{
}
teacher.h
#ifndef TEACHER_H
#define TEACHER_H
#include
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
void treat(); //treat槽的声明
signals:
};
#endif // TEACHER_H
teacher.cpp
#include "teacher.h"
#include
#include
Teacher::Teacher(QObject *parent)
: QObject{parent}
{
}
//treat槽的实现
void Teacher::treat(){
std::cout << "eat something" << std::endl;
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//含有两个成员变量
Teacher *teacher;
Student *student;
private:
Ui::Widget *ui;
void classOver();
};
#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便于析构
this->teacher = new Teacher(this);
this->student = new Student(this);
//将信号与槽进行链接
connect(this->student, &Student::hungry, this->teacher, &Teacher::treat);
classOver();
}
Widget::~Widget()
{
delete ui;
}
void Widget::classOver(){
emit this->student->hungry();
}
程序运行后,执行classOver()函数,其中触发了hungry信号,执行treat槽函数,从而在控制台上输出eat something
信号与槽的重载上一节的案例中,仅仅输出eat something。现在增加需求,考虑输出吃的食物的名称。
信号的参数个数可以多于槽的参数个数,但信号与槽的参数类型必须对应,这样可以保证槽能够正常接收到信号的参数。hungry()与treat()都是无参的,现在考虑对其进行重载,使它们均含有一个QString类型的参数代表学生想要吃的食物名称,对代码进行更改。
student.h中对hungry()进行重载
#ifndef STUDENT_H
#define STUDENT_H
#include
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
void hungry();
void hungry(QString foodName); //含参的信号
};
#endif // STUDENT_H
teacher.h对treat()进行重载
#ifndef TEACHER_H
#define TEACHER_H
#include
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
void treat();
void treat(QString foodName); //含参的槽函数
signals:
};
#endif // TEACHER_H
teacher.cpp
新增的代码中,含有foodName.toUtf8().data()这个语句。如果直接输出QString变量,会多出两个引号,所以需要将其转为utf8类型的字节数据再转为char *类型进行输出。
#include "teacher.h"
#include
#include
Teacher::Teacher(QObject *parent)
: QObject{parent}
{
}
void Teacher::treat(){
std::cout << "eat something" << std::endl;
}
//含参的treat()函数的实现
void Teacher::treat(QString foodName){
qDebug() << "eat" << foodName.toUtf8().data() << '\n';
}
widget.cpp
connect语句中需要传递函数指针,由于函数已经进行过重载,上一个案例中使用的方法无法表示函数的地址,所以需要事先创建好两个函数指针,再将其传入。这里需要注意创建函数指针的语法。
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->teacher = new Teacher(this);
this->student = new Student(this);
//创建函数指针
void(Student::*studentSignal)(QString) = &Student::hungry;
void(Teacher::*teacherSlot)(QString) = &Teacher::treat;
//将信号与槽相连。
connect(this->student, studentSignal, this->teacher, teacherSlot);
classOver();
}
Widget::~Widget()
{
delete ui;
}
void Widget::classOver(){
emit this->student->hungry("宫保鸡丁");
}
程序运行后,执行classOver()函数,其中触发了hungry信号,执行treat槽函数,从而在控制台上输出eat 宫保鸡丁
信号连接信号考虑下面的场景:点击按钮后学生感觉到饿,老师请客。
类似于信号连接槽,可以将信号与信号相连。将按钮点击信号连接到hungry,再将hungry连接到treat即可。
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->teacher = new Teacher(this);
this->student = new Student(this);
QPushButton *btn = new QPushButton("classOver", this);
void(Student::*studentSignal)(void) = &Student::hungry;
void(Teacher::*teacherSlot)(void) = &Teacher::treat;
connect(btn, &QPushButton::clicked, this->student, studentSignal);
connect(this->student, studentSignal, this->teacher, teacherSlot);
}
Widget::~Widget()
{
delete ui;
}
void Widget::classOver(){
emit this->student->hungry("宫保鸡丁");
}
Qt4的信号与槽
可以按照如下的Qt4写法进行编写。优点:参数直观。缺点:编译期间不做参数类型检测,而是程序运行中提示错误(原理为字符串匹配)。
//本行代码就含有参数不匹配的错误,需要删除"QString"
connect(this->student, SIGNAL(hungry()), this->teacher, SLOT(treat(QString)));
要注意的是,QT4写法只能将槽写在public slots中
#ifndef TEACHER_H
#define TEACHER_H
#include
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
public slots:
void treat();
void treat(QString foodName);
signals:
};
#endif // TEACHER_H
lambda表达式
C++11中的Lambda表达式用于创建匿名的函数对象
使用如下的代码声明一个Lambda表达式
[](){
};
使用如下的代码声明一个Lambda表达式并调用
[](){
}();
中括号内可以传递一些参数
- 空。没有使用任何函数对象参数。
- =。函数体内可以使用Lambda所在作用域范围内所有可见的局部变量(包含Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
- &。函数体内可以使用Lambda所在作用域范围内所有可见的局部变量(包含Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
- this。函数体内可以使用Lambda所在类中的成员变量。
- a。将a按值进行传递。按值传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数时const的。要修改传递进来的a的拷贝,需要添加mutable修饰符。
- &a。将a按引用进行传递。
- a, &b。将a按值进行传递,b按引用进行传递。
- =, &a, &b。a和b按引用进行传递,其余均按值传递。
- &, a, b。a和b按值进行传递,其余均按引用传递。
使用如下代码编写一个带有返回值的Lambda
int a = []() ->int {return 1000;}();
可以同时使用connect与Lambda来简化代码,这样写还可以省略connect语句的第三个参数。
QPushButton *btn = new QPushButton("close", this);
connect(btn, &QPushButton::clicked, [=](){
this->close();
});
断开连接
可以使用disconnect()函数断开信号与槽的连接,语法与connect()相同。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)