目录
[1 信号与槽简介](#1 信号与槽简介)
[2 如何在UI 文件里连接信号与槽](#2 如何在UI 文件里连接信号与槽)
[3 Qt 信号与槽机制](#3 Qt 信号与槽机制)
[3.1 QObject::connect() 信号与槽实现函数](#3.1 QObject::connect() 信号与槽实现函数)
[方式一:通过UI Designer会自动生成QObject::connect()](#方式一:通过UI Designer会自动生成QObject::connect())
[3.2 信号与槽的注意事项](#3.2 信号与槽的注意事项)
[(1) 一个信号可以连接多个槽](#(1) 一个信号可以连接多个槽)
[(2) 多个信号可以连接同一个槽](#(2) 多个信号可以连接同一个槽)
[(3) 一个信号可以连接另外一个信号](#(3) 一个信号可以连接另外一个信号)
[(4) 断开一切与 myObject 连接的信号或槽](#(4) 断开一切与 myObject 连接的信号或槽)
[(5) 断开所有连接到特定信号的东西](#(5) 断开所有连接到特定信号的东西)
[(6) 与指定的接收者断开连接](#(6) 与指定的接收者断开连接)
[4 如何在项目中创建信号和槽](#4 如何在项目中创建信号和槽)
[4.1 如何在项目里创建信号](#4.1 如何在项目里创建信号)
[4.2 如何在项目里创建槽](#4.2 如何在项目里创建槽)
[4.3 如何在项目中连接信号与槽](#4.3 如何在项目中连接信号与槽)
1 信号与槽简介
Qt的信号与槽机制是Qt框架中实现对象之间通信的一种方式,属于Qt的核心特性之一。在这个机制中,信号(signal)是由对象在发生了某种状态改变时发出的消息,槽(slot)是用来被信号触发的函数。
- **信号(Signal):**是由对象发出的一种特殊的公共成员函数,但它不是由程序员直接调用的,而是由Qt自己调用以响应某个事件。信号一旦发生,就会通知那些与之连接的槽函数。
- **槽(Slot):**可以是普通的成员函数,用于响应信号。槽可以与任何信号连接,而与信号发生的对象的类型无关。当与之相连的信号被触发时,槽函数就会被自动调用。
这种机制相比于传统的回调函数有很多优势,最主要的是它能够确保程序的松耦合和高级的事件处理能力。通过信号和槽,Qt开发者可以轻松地在不同的组件之间进行消息传递,从而使得应用程序架构更为清晰和灵活。
2 如何在UI 文件里连接信号与槽
在文章2.2节已进行了详细的描述:Qt教程 --- 2.1 如何使用Qt Designer 开发UI程序-CSDN博客
3 Qt 信号与槽机制
3.1 QObject::connect() 信号与槽实现函数
信号与槽关联是用 QObject::connect() 函数实现的,其基本格式是:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
- **connect() :**是 QObject 类的一个静态函数,而 QObject 是所有 Qt 类的基类,在实际调用时可以省略前面的限定符。
- sender: 是发射信号的对象的名称。
- **signal():**是信号名称。信号可以看做是特殊的函数, 需要带括号,有参数时还需要指明参。
- **receiver:**是接收信号的对象名称。
- **slot() :**是槽函数的名称,需要带括号,有参数时还需要指明参数。
方式一:通过UI Designer会自动生成QObject::connect()
通过第2节的方法设置好通过按钮关闭主窗口的信号和槽后,运行后在mainwindow.app ---> ui_mainwindow.h头文件中会自动生成QObject::connect() 函数,修改程序内容ui_mainwindow.h头文件也会自动更新。
方式二:手动方式编辑QObject::connect()
在mainwindows.cpp下,直接将方式一生成的代码复制到会报错,原因是pushButton和this->MainWindows找不到位置,pushButton是命名空间ui下的成员函数,this->MainWindows就在MainWindows命名空间下,写成this即可,具体代码如下:
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// QObject::connect(pushButton, SIGNAL(clicked()), this->MainWindow, SLOT(close()));
QObject::connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(close()));
}
代码修改位置如下:
3.2 信号与槽的注意事项
(1) 一个信号可以连接多个槽
当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行。
connect(pushButton, SIGNAL(clicked()), this, SLOT(hide());
connect(pushButton, SIGNAL(clicked()), this, SLOT(close());
这是当一个对象 pushButton 的被单击时,窗体有两个槽进行响应,一个 hide()用于隐藏主窗体,一个 close() 用于关闭主窗体。 这里只是举个例子,实际上当执行 close()后, hide()这个槽已经没有什么意义了, 因为已经程序退出了, 但是实际它有执行,因为它连接在 close()的前面。
(2) 多个信号可以连接同一个槽
多个信号可以连接同一个槽,例如设置3个pushButton 到设计的窗体里,同时也让它按3.1小节里的第一种方法连接信号与槽,把三个按钮的 clicked()信号对应连接到close()、hide()、lower()槽函数。
编译后可以在 ui_mainwindow.h 这个文件里自动生成如下的信号槽连接语句。
cpp
QObject::connect(pushButton, SIGNAL(clicked()), MainWindow, SLOT(close()));
QObject::connect(pushButton_2, SIGNAL(clicked()), MainWindow, SLOT(hide()));
QObject::connect(pushButton_3, SIGNAL(clicked()), MainWindow, SLOT(lower()));
(3) 一个信号可以连接另外一个信号
这样,当一个信号发射时,也会发射另外一个信号,实现某些特殊的功能。
connect(pushButton,SIGNAL(objectNameChanged(QString)),this,SIGNAL(windowTitelChanged(QString)));
pushButton
: 是信号的发送者,指的是一个按钮对象(假定是QPushButton
类型的)。SIGNAL(objectNameChanged(QString))
: 是发送者发出的信号,这里指的是pushButton
的objectNameChanged
信号,该信号在对象的objectName
属性改变时发出。objectNameChanged(QString)
传递一个QString
参数,表示新的对象名称。- **
this
:**指的是信号的接收者,在这个上下文中,通常指的是包含这行代码的对象(可能是一个窗口或者其他Qt对象)。 SIGNAL(windowTitleChanged(QString))
: 是接收者将要发出的信号。这意味着当pushButton
的objectName
属性发生变化时,不是调用一个槽函数,而是直接发出了一个新的信号windowTitleChanged(QString)
,同样传递一个QString
参数,这个信号需要在接收者这边定义。
(4) 断开一切与 myObject 连接的信号或槽
disconnect(myObject, 0, 0, 0);
(5) 断开所有连接到特定信号的东西
disconnect(myObject, SIGNAL(mySignal()), 0, 0);
(6) 与指定的接收者断开连接
disconnect(myObject, 0, myReceiver, 0);
4 如何在项目中创建信号和槽
4.1 如何在项目里创建信号
(1) 新建项目命名为 03_signal_slot_example, 同时取消勾选*ui 文件, 其他步骤不变。
(2) 由于信号只需声明, 无需定义。 所以我们只需要在 mianwindow.h 里声明信号即可。 代码如下,如下图黑色加粗部分代码就是创建的信号。这里创建一个 void pushButtonTextChanged();信号。完整代码如下:
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void PushButtonTextChanged();
};
#endif // MAINWINDOW_H
4.2 如何在项目里创建槽
创建槽的方法也很简单, 也是直接在 mianwindow.h 里直接声明槽,在 mianwindow.cpp 里
实现槽的定义,就是C++创建函数的流程。
槽有以下特点:
- 槽可以是任何成员函数、普通全局函数、静态函数。
- 槽函数和信号的参数和返回值要一致。
(1) 在mianwindow.h 声明信号 void pushButtonTextChanged();所以我们声明的槽函数必须是无返回值类型 void,和无需参数,同时还声明一个按钮点击的槽。此外还声明一个 QPushButton 对象 pushButton。完整代码如下:
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// 引入 QPushButton文件
#include <QPushButton>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void PushButtonTextChanged();
public slots:
// 声明一个槽函数
void changeButtonText();
// 声明按钮点击的槽函数
void pushButtonClicked();
private:
// 声明一个对象 pushButton
QPushButton *pushButton;
};
#endif // MAINWINDOW_H
(2) 在 mainwindow.cpp 里 实 现 声 明 的 槽 函 数 void changeButtonText(); 和 void pushButtonClicked(); 同时还实例化了 pushButton 对象。同时设置按钮的文字大小、边界和颜色参数。
4.3 如何在项目中连接信号与槽
在2.3节介绍了项目中连接信号与槽的函数。在 mainwindow.cpp 中补充信号槽连接的代码。 mainwindow.cpp完整代码如下:
cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 设置MainWindow尺寸
this->resize(800,600);
pushButton = new QPushButton(this);
// 设置按钮文字
pushButton->setText("我是一个按钮");
// 设置按钮位置和尺寸
pushButton->setGeometry(340, 50, 120, 60);
// 设置按钮文字颜色
pushButton->setStyleSheet("QPushButton { color: red; }");
// 信号与槽连接
connect(pushButton, SIGNAL(clicked()), this,SLOT(pushButtonClicked()));
connect(this, SIGNAL(PushButtonTextChanged()), this, SLOT(changeButtonText()));
}
MainWindow::~MainWindow()
{
}
void MainWindow::pushButtonClicked()
{
emit PushButtonTextChanged();
}
void MainWindow::changeButtonText()
{
pushButton->setText("被点击了");
// 设置按钮文字颜色
pushButton->setStyleSheet("QPushButton { color: green; }");
}
最后实现的效果如下,点击前文字为红色,点击后为绿色。