Qt中的信号槽

2023-09-20 21:22:47 浏览数 (1)

一、信号槽的概念

类似于一些其它的编程语言或框架中的回调机制,信号槽是Qt基于C 语法新增的特性,使用起来非常方便,可以完成不同对象之间的通信。

信号槽的使用需要有以下两个条件:

  1. 通信的对象必须**继承自QObject类**,**QObject是Qt所有内置类型的基类**。
  2. 类中要有**Q_OBJECT宏**

二、函数原型

信号槽需要连接后才能触发,因此信号槽的**核心是连接函数,**连接函数是一个静态成员函数。

参数1:**发射者**,发射者是一个对象,此对象发射信号函数,**作为信号槽的触发条件。**

参数2:**信号函数**,参数1中的发射者发射出的信号函数,**作为信号槽的触发条件**。**需要使用 SIGNAL()包裹函数名称**

参数3:**接收者**,接收者是一个对象,此对象执行槽函数,**作为信号槽的执行结果**。

参数4:**槽函数**,参数3中接收者要执行的槽函数,**作为信号槽的执行结果。需要使用SLOT() 包裹函数名称。**

接收者绑定了发射者的信号函数,一旦发射者发射信号函数,接收者就执行槽函数。

三、连接方式

为了方便讲解,依次使用三种方式进行信号槽的连接。 - 自带信号 → 自带槽- 自带信号 → 自定义槽- 自定义信号 → 槽

3.1 自带信号 → 自带槽

这种方式是最简单的一种连接方式,因为信号函数和槽函数Qt都内置了,只需要程序员从文档中找到对应函数连接即可。

【例子】点击按钮,关闭窗口。

分析:先找因果关系的四个参数。

参数1:发射者,按钮对象

参数2:信号函数,点击

参数3:接收者,窗口对象

参数4:槽函数,关闭

mywidget.h

代码语言:javascript复制
#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QPushButton>
#include <QWidget>

class MyWidget : public QWidget
{
    Q_OBJECT

public:
    MyWidget(QWidget *parent = nullptr);
    ~MyWidget();
private:
    QPushButton *btn;
};
#endif // MYWIDGET_H

mywidget.cpp

代码语言:javascript复制
#include "mywidget.h"

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
{
    setFixedSize(400,400);
    // 实例一个按钮对象
    btn = new QPushButton("自带信号,自带槽演示", this);
    btn->move(100,100);
    // 连接槽和函数
    // 完成点击按钮关闭当前窗口
    // 标准写法
    connect(btn, SIGNAL(clicked()), this, SLOT(close()));
}

MyWidget::~MyWidget()
{
}

main.cpp

代码语言:javascript复制
#include "mywidget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyWidget w;
    w.show();
    return a.exec();
}

3.2 自带信号 → 自定义槽

在实际的开发中,Qt不可能内置所有的函数,特别是槽函数,更多的情况是需要用户自定义一个槽函数来实现特定的功能,这种方式也是最常见的一种信号槽连接方式。

需要注意的是,槽函数是一种特殊的成员函数,实现槽函数的方式与普通成员函数类似。

注意:一定要先链接再触发信号 不然你虽然触发了信号但是接收者没有进行链接就触发不了槽函数

【例子】点击按钮,向右下方移动窗口并输出当前的窗口坐标。

参数1:按钮对象

参数2:clicked

参数3:窗口对象

参数4:自定义槽函数

dialog.h

代码语言:javascript复制
#ifndef DIALOG_H
#define DIALOG_H
 
#include <QDialog>
#include <QPushButton>
#include <QDebug>
 
class Dialog : public QDialog
{
    Q_OBJECT
 
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
 
private:
    QPushButton *btn;
 
private slots: // 私有槽函数
    // 声明自定义槽函数
    void mySlot();
};
 
#endif // DIALOG_H

dialog.cpp

代码语言:javascript复制
#include "dialog.h"
 
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn = new QPushButton("向右下方移动",this);
    btn->setGeometry(100,100,100,100);
 
    // 连接信号槽
    //    参数1:按钮对象 btn
    //    参数2:clicked
    //    参数3:窗口对象 this
    //    参数4:自定义槽函数 mySlot
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));//类内通过this指针找到w,
          第三个参数为什么是this因为自定义信号槽函数属于Dialog类而这个类只有一个对象就是w,
          类内想要调w就必须用this
}
//法一:手写 法二:再定义中鼠标中点击重构
void Dialog::mySlot()//类内声明类外定义必须加作用域限定符 
{
    // 先获得当前窗口的坐标
    int x = this->x();
    int y = this->y();
    // 增加后移动
    move(x 10,y 10);
    // 输出当前坐标
    qDebug() << x 10 << "," << y 10;
}
 
Dialog::~Dialog()
{
    
}

3.3 自定义信号 → 槽

这种做法主要用于后期一些稍微复杂的场景,现在讲解无法使用合适案例演示,因此讲解的过程中并不是最优解,属于强行使用。

【例子】点击按钮,关闭窗口。

之前的思路:

现在的思路:

现在的思路需要有两个信号槽的连接,在自定义槽函数中要手动发射一个自定义信号函数,信号函数是一种非常特殊的函数,信号函数只有声明,没有定义;信号函数没有权限。

首先按钮与窗口进行链接connect 再点击按钮 按钮发射一个信号 由于两者绑定所以窗口会收到这个信号并触发槽函数,然后再去链接connect窗口与窗口本身就是自己链接自己 上一个触发的槽函数里面是一个自定义信号 然后发射这个自定义信号 窗口接受 并执行相应的槽函数 

dialog.h

代码语言:javascript复制
#ifndef DIALOG_H
#define DIALOG_H

#include <QLineEdit>
#include <QPushButton>
#include <QWidget>

class Dialog : public QWidget
{
    Q_OBJECT
public:
    explicit Dialog(QWidget *parent = nullptr);
private slots:
    void mySlot(); // 自定义槽
    void mySlot1();

signals:
    void mySignal(); // 自定义信号
private:
    QPushButton *btn;
    QLineEdit *txt;

};

#endif // DIALOG_H

dialog.cpp

代码语言:javascript复制
#include "dialog.h"

Dialog::Dialog(QWidget *parent) : QWidget(parent)
{
    // 设置窗口大小
    setFixedSize(600,400);
    // 实例化一个QLineEdit对象
    txt = new QLineEdit(this);
    txt->setGeometry(260,100,170,50);
    // 实例化一个按钮对象
    btn = new QPushButton("自定义槽和信号操作",this);
    // 设置位置和大小
    btn->setGeometry(100,100,150,50);
    // 连接信号和槽函数
    connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));
    // 给窗体连接自定义信号和自带槽函数
    connect(this, SIGNAL(mySignal()), this, SLOT(mySlot1()));
}

void Dialog::mySlot()
{
    // 手动触发自定义信号
    emit mySignal();
}

void Dialog::mySlot1()
{
    txt->setText("触发了自定义信号和槽函数");
}

【小结】

信号槽是个较新的概念,需要花点时间细细品味,细嚼慢咽,然后在理解的基础上运用。

c++

0 人点赞