欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Qt开发】Qt信号与槽 示例

程序员文章站 2024-03-16 18:46:10
...

假设基于这样的一个情况:

在某一个程序里有两个主要的两个逻辑功能部分---UI交互的功能块和用于网络通信的网络功能块。当网络中有新的消息到达时,网络功能块需要通知UI刷新信息的显示;当用户输入新的操作命令或信息时,UI功能块将通过调用网络程序来进行数据的传送。

在非Qt程序中,我们一般是通过函数的回调或事件监听机制来实现这样的程序。打个比方,假设有类A和类B,类A对象中存有类B对象的指针,同时将自身的对象指针传到类B中去,这样便可以实现了函数的回调;A对象可以调用B的公有方法,同时B也可以根据具体情况来回调A的公有方法。

这种方式类似于通用设计模式中的观察者模式,只是观察者模式提供了更抽象的封装而已,比如对象之间互传的指针都是基于动态绑定的对象指针。

回到正题,在Qt程序中更偏向于使用信号与槽的机制来解决这样的问题。当然信号与槽机制的作用远远不止这些。

基于这种机制,不同对象之间可以发送信号,也可以接受信号,接收信号的方法称为槽。概括来说它有几个特性:(1)相对于普通的回调机制,它没有复杂的指针对象,只是指定了发送信号和接受信号的对象。(2)一个槽可以接收多个对象发出来的信号,一个信号也可以与多个槽连接。(3)在跨线程或进程的函数调用中,信号与槽的机制显得更为安全和灵活,而省去了一些非安全的显式指针调用。

下面是一个简单的例子,演示信号与槽的工作原理。

(1)定义信号

#include <QObject>

class A : public QObject
{
    Q_OBJECT

public:
    A(QObject* parent = 0);
    
signals:
    void message_arrive(QString msg);
};

#include "a.h"

A::A(QObject* parent) : QObject(parent)
{
}

作为signal与slot中的一个参与者对象,它必须是QObject对象,也就是它必须要从QObject中派生而来。同时也要求在类声明中添加宏Q_OBJECT的声明,宏Q_OBJECT的作用是默认实现了Qt对象模型所需的几个关键函数。

关于信号,有几个特点:(1)信号的定义关键字是signals,不需要添加访问级别的关键字修饰,因信号总是被默认为public的,以便在不同类之间通信。(2)信号总是只有声明,而没有定义体的,这就好比C++的纯虚函数一样。(3)信号和槽之间传递的参数必须对应。(4)信号的返回类型总是void,即没有返回值。

(2)定义槽

#include <QObject>

class B : public QObject
{
    Q_OBJECT

public:
    B(QObject* parent = 0);
    
public slots:
    void reflash_text(QString msg);
};
#include "b.h"

B::B(QObject* parent) : QObject(parent)
{
}

void B::reflash_text(QString msg)
{
    // TODO:接收信号并处理参数
}

槽的访问级别可以设置成public, proteced, private,这个根据具体情况而定;同时需要实现相应的函数体。当然,信号与

槽也可以同时定义在同一个对象中。

(3)连接信号与槽

方法调用:QObject::connect(const QObject *asender, const char *asignal,const QObject *areceive, const char *asignal,Qt::ConnectionType atype)。最后一个参数是可选的,代表采取的连接类型(连接类型会设计到安全性问题,比如不同线程间的信号与槽连接类型普遍采取QueuedConnection等)。

对于上面的示例,则可以这样连接:

QObject::connect(a, SIGNAL(message_arrive(QString)), this, SLOT(reflash_text(QString)));

其中a为类A的一个对象的指针; this指向类B的一个对象本身,也就是说这个函数connect()在B中调用。