目录
信号和槽是Qt框架中一种用于处理事件和实现对象间通信的机制。这种机制使得对象能够在特定事件发生时通知其他对象,并让其他对象能够响应这些事件。
信号和槽的基本概念:
信号(Signal):
- 信号是对象发出的通知,表示某个特定事件发生了。信号通常由
emit
关键字发射。- 一个信号可以与多个槽关联,多个对象可以连接到同一个信号。
槽(Slot):
- 槽是一个特殊的成员函数,用于处理与之关联的信号。槽函数的名称以
on_
开头是一种常见的命名约定,但并非必须。- 槽函数的签名必须与与之关联的信号的签名相匹配。
信号和槽的关系:
? ? ? ? 在Qt中信号和槽函数都是独立的个体,本身没有任何联系,但是由于某种特性需求我们可以将二者连接到一起,好比牛郎和织女想要相会必须要有喜鹊为他们搭桥一样。在Qt中我们需要使用QOjbect类中的connect函数进二者的关联。
? ? ? ? 信号和槽是Qt框架中一种强大的机制,使得对象能够以灵活而松散耦合的方式进行通信和事件处理。这种机制在Qt应用程序中广泛应用,特别是在用户界面开发和多线程编程中。
连接信号和槽的connect()函数原型如下:
connect(const QObject *sender, &QObject::signal, const QObject *receiver, &QObject::method);
sender
: 这是发射信号的对象。当sender
的mySignal
信号被发射时,与之关联的槽函数将被调用。
signal:属于sender对象, 信号是一个函数, 这个参数的类型是函数指针, 信号函数地址
receiver
: 这是接收信号的对象。当sender
对象发射mySignal
信号时,与之连接的receiver
对象的mySlot
槽函数将被调用。
method: 属于receiver对象, 当检测到sender发出了signal信号,receiver对象调用method方法,信号发出之后的处理动作
?
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); connect(ui->closeBut,&QPushButton::clicked,this,&MainWindow::close); } MainWindow::~MainWindow() { delete ui; }
这段代码是在Qt中使用
connect
函数,将一个按钮的点击事件(clicked信号)与MainWindow
类的close
槽函数连接起来。当按钮被点击时,MainWindow
的close
槽函数将被调用,关闭主窗口。
connect
函数:connect(ui->closeBut, &QPushButton::clicked, this, &MainWindow::close);
ui->closeBut
: 这是一个指向QPushButton
对象的指针,表示窗口中的一个按钮。&QPushButton::clicked
: 这是按钮的clicked
信号。QPushButton
类的clicked
信号在按钮被点击时触发。this
: 这是当前对象,即MainWindow
的实例。&MainWindow::close
: 这是MainWindow
类的close
槽函数。在这里,它与按钮的clicked
信号关联。
close
槽函数:void MainWindow::close() { // 槽函数的实现 QMainWindow::close(); // 关闭主窗口 }
当按钮被点击时,
MainWindow::close
槽函数被调用,关闭主窗口。总体而言,这段代码建立了一个很简单的连接,使得当按钮被点击时,主窗口将被关闭。
自定义信号:
? ? ? ? 在Qt中,可以自定义信号和槽,以便在你的应用程序中实现自定义的事件处理机制,同样还是使用connect()对自定义的信号槽进行连接。
? ? ? ? 如果想要在QT类中自定义信号槽, 需要满足一些条件, 并且有些事项也需要注意:
- 要编写新的类并且让其继承Qt的某些标准类
- 这个新的子类必须从QObject类或者是QObject子类进行派生
- 在定义类的头文件中加入 Q_OBJECT 宏
? ? ? ? 在Qt中信号的本质是事件, 但是在框架中也是以函数的形式存在的, 只不过信号对应的函数只有声明, 没有定义。如果Qt中的标准信号不能满足我们的需求,可以在程序中进行信号的自定义,当自定义信号对应的事件产生之后,认为的将这个信号发射出去即可(其实就是调用一下这个信号函数)。
自定义槽:
? ? ? ?槽函数就是信号的处理动作,在Qt中槽函数可以作为普通的成员函数来使用。如果标准槽函数提供的功能满足不了需求,可以自己定义槽函数进行某些特殊功能的实现。自定义槽函数和自定义的普通函数写法是一样的。
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); m_me=new Me; m_girl=new girlfriend; // 连接女朋友对象的hungry信号到Me对象的eat槽函数 connect(m_girl,&girlfriend::hungry,m_me,&Me::eat); // 连接女朋友对象的hungry信号到MainWindow对象的eatSlot槽函数 connect(m_girl,&girlfriend::hungry,this,&MainWindow::eatSlot); // 连接按钮的clicked信号到MainWindow对象的hungrySlot槽函数 connect(ui->hungry,&QPushButton::clicked,this,&MainWindow::hungrySlot); // 连接按钮的clicked信号到MainWindow对象的close槽函数 connect(ui->closeBut,&QPushButton::clicked,this,&MainWindow::close);//通过点击事件 关闭窗口 } MainWindow::~MainWindow() { delete ui; } void MainWindow::hungrySlot() { //发射自定义信号 m_girl->hungry(); } void MainWindow::eatSlot() { qDebug()<<"我带你去吃海鲜..."; }
这个例子创建了一个主窗口,包含两个按钮(ui->hungry
和 ui->closeBut
)。其中,ui->hungry
按钮模拟女朋友饿了,点击按钮会发射女朋友对象的 hungry
信号。ui->closeBut
按钮用于关闭窗口。
连接的关系如下:
ui->hungry
按钮被点击时,会触发 MainWindow::hungrySlot
槽函数,该槽函数通过发射 girlfriend::hungry
信号通知女朋友对象饿了。hungry
信号被连接到两个槽函数:Me::eat
和 MainWindow::eatSlot
。这两个槽函数在信号被触发时执行相应的操作。?Lambda 表达式是一种在 C++ 中引入的匿名函数的语法糖,它允许在需要函数对象的地方直接定义一个匿名函数,而不必显式地声明一个函数,Qt是完全支持c++语法的, 因此在Qt中也可以使用Lambda表达式。。Lambda 表达式的基本形式如下:
[capture](parameters) -> return_type { // 函数体 }
其中:
capture
:捕获列表,用于指定在 lambda 表达式中可见的外部变量。可以通过值捕获、引用捕获,或者混合捕获。parameters
:参数列表,与普通函数的参数列表类似。return_type
:返回类型,指定 lambda 表达式的返回类型。函数体
:包含实际代码的部分。关于Lambda表达式的细节介绍:
1.捕获列表: 捕获一定范围内的变量
- [] - 不捕捉任何变量
- [&] - 捕获外部作用域中所有变量, 并作为引用在函数体内使用 (按引用捕获)
- [=] - 捕获外部作用域中所有变量, 并作为副本在函数体内使用 (按值捕获)
- 拷贝的副本在匿名函数体内部是只读的
- [=, &foo] - 按值捕获外部作用域中所有变量, 并按照引用捕获外部变量 foo
- [bar] - 按值捕获 bar 变量, 同时不捕获其他变量
- [&bar] - 按引用捕获 bar 变量, 同时不捕获其他变量
- [this] - 捕获当前类中的this指针
- 让lambda表达式拥有和当前类成员函数同样的访问权限
- 如果已经使用了 & 或者 =, 默认添加此选项
2.参数列表: 和普通函数的参数列表一样
3.opt 选项 –> 可以省略
- mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)
- exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用throw();
4.返回值类型:
- 标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
5.函数体:
- 函数的实现,这部分不能省略,但函数体可以为空。
1.Lambda 表达式不带参数和返回值:
[] { // 代码块 };
2.Lambda 表达式带参数:
[](int x, int y) { return x + y; };
3.Lambda 表达式带参数和返回值:
[](int x, int y) -> int { return x + y; };
4.Lambda 表达式带捕获列表:
int a = 10; [](int x) { return x + a; };