目录
信号槽使用拓展
示例1(一个信号可以对应多个槽函数)(在上篇文章的代码中进行修改):
示例2(用信号连接信号):
信号槽的连接方式
示例:
Lambda表达式
语法格式
定义和调用
信号槽使用拓展
一个信号可以连接多个槽函数, 发送一个信号有多个处理动作
需要写多个connect()连接
槽函数的执行顺序是随机的,和connect函数的调用顺序没有关系
信号的接收者可以是一个对象,也可以是多个对象
一个槽函数可以连接多个信号,多个不同的信号,处理动作是相同的
需要写多个connect()连接
信号可以连接信号
信号接收者可以不处理接收的信号,而是继续发射新的信号,这相当于传递了数据,并没有对数据进行处理
connect(const QObject *sender, &QObject::signal,
const QObject *receiver, &QObject::siganl-new);
信号槽是可以断开的
disconnect(const QObject *sender, &QObject::signal,
const QObject *receiver, &QObject::method);
示例1(一个信号可以对应多个槽函数)(在上篇文章的代码中进行修改):
在mainwindow.h中再添加一个槽函数
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "test.h"
#include "test01.h"
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//添加need按钮的槽函数
void needSlot();
void need1Slot();
private:
Ui::MainWindow *ui;
Test01* m_whatnd;
Test* m_need;
};
#endif // MAINWINDOW_HS
到mainwindow.cpp中定义并进行连接
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_whatnd = new Test01;
m_need = new Test;
connect(m_need,&Test::need,m_whatnd,&Test01::what_need);
connect(m_need,&Test::need,this,&MainWindow::need1Slot);
connect(ui->need,&QPushButton::clicked,this,&MainWindow::needSlot);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::needSlot()
{
//发射自定义信号
emit m_need->need();
}
void MainWindow::need1Slot()
{
qDebug()<<"你什么都不需要";
}
运行程序,应用程序输出两条语句:
示例2(用信号连接信号):
对mainwindow.cpp中的信号连接进行修改
运行结果和原先一样:
信号槽的连接方式
Qt5的连接方式
// 语法:
QMetaObject::Connection QObject::connect(
const QObject *sender, PointerToMemberFunction signal,
const QObject *receiver, PointerToMemberFunction method,
Qt::ConnectionType type = Qt::AutoConnection);
// 信号和槽函数也就是第2,4个参数传递的是地址, 编译器在编译过程中会对数据的正确性进行检测
connect(const QObject *sender, &QObject::signal,
const QObject *receiver, &QObject::method);
示例:
在test01.h中进行函数重载
在mainwindow.cpp中做以下修改
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_whatnd = new Test01;
m_need = new Test;
void(Test::*test1)(QString) = &Test::need;
void(Test::*test2)(QString) = &Test::need;
void(Test01::*mypoint)(QString) = &Test01::what_need;
connect(m_need,test2,m_whatnd,mypoint);
connect(m_need,test2,this,&MainWindow::need1Slot);
//信号连接信号
//connect(ui->need,&QPushButton::clicked,m_need,&Test::need);
connect(ui->need,&QPushButton::clicked,this,&MainWindow::needSlot);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::needSlot()
{
//发射自定义信号
emit m_need->need();
m_need->need("吃饭");
}
void MainWindow::need1Slot()
{
qDebug()<<"你什么都不需要";
}
运行结果:
Lambda表达式
Lambda表达式是 C++ 11 最重要也是最常用的特性之一,是现代编程语言的一个特点,简洁,提高了代码的效率并且可以使程序更加灵活,Qt是完全支持c++语法的, 因此在Qt中也可以使用Lambda表达式。
语法格式
Lambda表达式就是一个匿名函数, 语法格式如下:
[capture](params) opt -> ret {body;};
- capture: 捕获列表
- params: 参数列表
- opt: 函数选项
- ret: 返回值类型
- body: 函数体
关于Lambda表达式的细节介绍:
- 捕获列表: 捕获一定范围内的变量
[]
- 不捕捉任何变量[&]
- 捕获外部作用域中所有变量, 并作为引用在函数体内使用 (按引用捕获
)[=]
- 捕获外部作用域中所有变量, 并作为副本在函数体内使用 (按值捕获
)- 拷贝的副本在匿名函数体内部是只读的
[=, &foo]
- 按值捕获外部作用域中所有变量, 并按照引用捕获外部变量 foo[bar]
- 按值捕获 bar 变量, 同时不捕获其他变量[&bar]
- 按引用捕获 bar 变量, 同时不捕获其他变量[this]
- 捕获当前类中的this指针- 让lambda表达式拥有和当前类成员函数同样的访问权限
- 如果已经使用了 & 或者 =, 默认添加此选项
- 参数列表: 和普通函数的参数列表一样
- opt 选项 –>
可以省略
- mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)
- exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用throw();
- 返回值类型:
- 标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略
- 函数体:
- 函数的实现,这部分不能省略,但函数体可以为空。
定义和调用
因为Lambda表达式是一个匿名函数, 因此是没有函数声明的, 直接在程序中进行代码的定义即可, 但是如果只定义匿名函数在程序执行过程中是不会被调用的。
// 匿名函数的定义, 程序执行这个匿名函数是不会被调用的
[](){
qDebug() << "hello, 我是一个lambda表达式...";
};
// 匿名函数的定义+调用:
int ret = [](int a) -> int
{
return a+1;
}(100); // 100是传递给匿名函数的参数
在Lambda
表达式的捕获列表中也就是 []
内部添加不同的关键字, 就可以在函数体中使用外部变量了。
// 在匿名函数外部定义变量
int a=100, b=200, c=300;
// 调用匿名函数
[](){
// 打印外部变量的值
qDebug() << "a:" << a << ", b: " << b << ", c:" << c; // error, 不能使用任何外部变量
}
[&](){
qDebug() << "hello, 我是一个lambda表达式...";
qDebug() << "使用引用的方式传递数据: ";
qDebug() << "a+1:" << a++ << ", b+c= " << b+c;
}();
// 值拷贝的方式使用外部数据
[=](int m, int n)mutable{
qDebug() << "hello, 我是一个lambda表达式...";
qDebug() << "使用拷贝的方式传递数据: ";
// 拷贝的外部数据在函数体内部是只读的, 如果不添加 mutable 关键字是不能修改这些只读数据的值的
// 添加 mutable 允许修改的数据是拷贝到函数内部的副本, 对外部数据没有影响
qDebug() << "a+1:" << a++ << ", b+c= " << b+c;
qDebug() << "m+1: " << ++m << ", n: " << n;
}(1, 2);
总结:文章中主要介绍了Qt中的信号槽, 主要内容包括: 信号槽的拓展
, Lambda表达式
。