Qt 信号与槽研究2

原创 2016年05月30日 12:16:24

一个信号对槽的调用: 会比直接函数调用耗费更多的时间/空间;
但是,信号与槽实现了对象之间的松耦合. 使用灵活,方便。比较符合人的思维方式。

这就是以易用性来换取时间或空间。

下面实例讲解QT signal, slot, connect, emit 的含义。

先上代码: 最简单代码,我不喜欢复杂的。

两个类,一个A, 一个B, 声明两个对象,一个a,一个b. a 发信号调用b的槽函数。

$ cat a.h
#include <QObject>  

class A : public QObject  
{  
Q_OBJECT  
public:  
	A(QObject* parent = 0){(void)parent;} // 空构造
	void aFunc();  // 在这个函数里发射信号
signals :  
	void SendString(QString msg);  
	void SendInt(int i);  
};  
$ cat a.cpp
#include "a.h"
void A::aFunc()
{
	emit SendString("this is a str");
	emit SendInt(8);
}

B 类声明和实现

cat b.h
#include <QObject>  
class B : public QObject  
{  
Q_OBJECT  
	public:  
		B(QObject* parent = 0){(void)parent;};  
	public slots:  
		void ReceiveString(QString msg);  
		void ReceiveOtherSlot(float f);
		void ReceiveInt(int i);  
};  
$ cat b.cpp
#include <QDebug>
#include "b.h"

void B::ReceiveString(QString msg)
{
	qDebug() << msg <<endl;
}

void B::ReceiveOtherSlot(float f)
{
	qDebug() << f <<endl;
}
void B::ReceiveInt(int i)
{
	qDebug() << i <<endl;
}

测试程序:

$ cat main.cpp
#include <QApplication>  
#include "a.h"
#include "b.h"
  
int main(int argc, char *argv[])  
{  
    QApplication app(argc, argv);
    A a;
    B b;
    QObject::connect(&a, SIGNAL(SendString(QString)), &b, SLOT(ReceiveString(QString)));
    QObject::connect(&a, SIGNAL(SendInt(int)), &b, SLOT(ReceiveInt(int)));
    a.aFunc();  // 在这个函数中发射信号
    return app.exec();  
}       

解释一下几个概念:
signals 是什么?
    signals 是一系列信号,
    实际上是一个函数原型声明,但是没有函数实现。
    signals 无需声明公有,私有属性.
    实际上,函数实现在其它对象中,什么样子不关心。
    发射一个信号,就是调用一个或多个其它对象中的函数。
    到底哪些函数被调用,是由QObject::connect() 所决定

slots 是什么?
    slots 是一系列槽函数. 槽函数与普通函数没有区别,
    只是它可以接受信号,可以被其它对象所调用。
    slots 具有public,private,protect 属性,决定其可连接属性

connect 是什么?
connect 是QObject 一个函数,用以登记两个对象的连接属性,它使用的SIGNAL 是一个宏
        用于将后面的函数变换为字符串, SLOT 也是一个宏,用于将后面函数变换为字符串,

        使得QOjbect可以登记 两个函数名称。 将一个对象的信号于另一个对象的槽函数联系起来。

 注意: connect 连接的信号和槽是函数原型, 函数参数不用带形参名称,否则连接不上,会提示无此信号或槽。


signal 的使用
----------------------------------------
emit SendInt(8);
----------------------------------------
1. emit 是什么?, emit 是个宏,空的宏, #define emit ""
2. signal 如何调用到slot 函数

用gdb 调试这个程序.  我们在 B::ReceiveInt 设置断点, 断下后:
(gdb) bt
  #0  B::ReceiveInt (this=0x7fffffffdc80, i=8) at b.cpp:15
  #1  0x0000000000402575 in B::qt_static_metacall (_o=0x7fffffffdc80, _c=QMetaObject::InvokeMetaMethod, _id=2, _a=0x7fffffffdbf0) at      moc_b.cpp:53
  #2  0x00007ffff6a31fdf in QMetaObject::activate (sender=0x7fffffffdc70, m=0x402840 <A::staticMetaObject>, local_signal_index=1,         argv=0x7fffffffdbf0) at kernel/qobject.cpp:3539
  #3  0x00000000004023f4 in A::SendInt (this=0x7fffffffdc70, _t1=8) at moc_a.cpp:106
  #4  0x00000000004018bc in A::aFunc (this=0x7fffffffdc70) at a.cpp:5


从底向上分析:
1.  在a.cpp:5, 调用了    
    emit SendInt(8); 对应于:
    A::SendInt (this=0x7fffffffdc70, _t1=8) , 这实际上是moc_a.cpp 中的一个函数,属于A 类
2. 在 moc_a.cpp:106, 调用了
    QMetaObject::activate(this, &staticMetaObject, 1, _a); 对应于: kernel/qobject.cpp:3539
    QMetaObject::activate (sender=0x7fffffffdc70, m=0x402840 <A::staticMetaObject>, local_signal_index=1, argv=0x7fffffffdbf0)
    该cpp 文件定义了QObject, QMetaObject 类的几个成员函数。函数原型
    void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, void **argv)
    可以看到sender 是a, QMetaObject 是A::staticMetaObject, local_signal_index 是1,并带有参数传给了该函数。

3. 在 kernel/qobject.cpp:3539, 调用了
    callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);
    对应于
    B::qt_static_metacall (_o=0x7fffffffdc80, _c=QMetaObject::InvokeMetaMethod, _id=2, _a=0x7fffffffdbf0)
    函数原型:void B::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)

    可见,QMetaObject 类负责寻径,找到receiver 对象为 b, 类型QMetaObject::InvokeMetaMethod, 接受_id 为2, 带参数.
    它是怎么找的,当然是QObject::connect 注册过的。
    这个被调用函数, 在moc_b.cpp 中。

4.  在moc_b.cpp:53 调用了
    case 2: _t->ReceiveInt((*reinterpret_cast< int(*)>(_a[1]))); break;
    对应于
    B::ReceiveInt (this=0x7fffffffdc80, i=8)
    函数原型: void B::ReceiveInt(int i)
    可见,该函数通过参数_id=2, 找到了正确的槽函数。并传递参数调用槽函数。

简单梳理一下: 对象a(signal)->moc_a->qobject->moc_b->b(SLOT).对象b(slots)

两边是moc辅助函数, 中间夹着qobject类, qobject 根据注册的connect 函数负责send, receive的钩挂和寻径

至此,路径分析就算清楚了。



版权声明:本文为博主原创文章,未经博主允许不得转载。

Qt学习心得——信号与槽的认识1

Qt学习心得——信号与槽的认识1       信号与槽的主要实现的功能是对界面中按钮进行定义,比如主界面中有个按钮pushbutton,并设置其显现名称为“计算”,那需要定义一个当这个按钮被点击时的功...
  • wwoll
  • wwoll
  • 2016年10月24日 13:00
  • 446

Qt 信号与槽研究:

Qt 信号与槽研究: author: hjjdebug date: 2015年 08月 17日 星期一 09:36:31 CST ----------------------------------...
  • hejinjing_tom_com
  • hejinjing_tom_com
  • 2015年08月17日 09:52
  • 642

Qt信号与槽实现原理

有网友抱怨: 哪个大牛能帮帮我,讲解一下信号槽机制的底层实现? 不要那种源码的解析,只要清楚的讲讲是怎么发送信号,怎么去选择相应的槽,再做出反应。也就是类似于一个信号槽的相应流程。。。求解啊!!! 看...
  • fuyunzhishang1
  • fuyunzhishang1
  • 2015年09月10日 16:37
  • 9939

【QT】深入qt信号与槽实现原理

1、先上示例代码先上示例代码直观地感受一下qt信号与槽的用法,后面再详细解释。通过QtCreator创建一个Qt Widget工程(没有创建ui文件,其它选项为默认值),工程名为SS,最后在SS目录下...
  • iEearth
  • iEearth
  • 2017年07月01日 05:19
  • 2974

QT跨线程的信号与槽

QT程序是由主线程更新界面 若在主线程做一些耗时的操作,会导致界面暂时卡死 所以要把耗时的操作放到一个后台线程中去做 最好的方式是主线程发出信号,后台线程去干活 当后台线程干完活时发出信号,主线程进行...
  • Sidyhe
  • Sidyhe
  • 2015年08月19日 14:41
  • 1782

QT信号与槽的简单实例

假设基于这样的一个情况: 在某一个程序里有两个主要的两个逻辑功能部分---UI交互的功能块和用于网络通信的网络功能块。当网络中有新的消息到达时,网络功能块需要通知UI刷新信息的显示;当用户输入新的操...
  • vectim
  • vectim
  • 2017年05月18日 23:27
  • 322

Qt信号与槽的自动关联

版权所有,转载时请注明出处和作者联系方式文章出处:http://blog.csdn.net/skyhawk452作者联系方式:汪应豪 sky_hawk2010@yahoo.cn     为了实现槽函数...
  • skyhawk452
  • skyhawk452
  • 2011年01月06日 22:51
  • 856

QT5 中的信号与槽新的写法

Qt4中最常用的信号槽写法: connect(obj1, SIGNAL(fun1(param1, param2,...)), obj2, SLOT(fun2(param1,...))); //...
  • zhaolushandong
  • zhaolushandong
  • 2017年01月07日 17:03
  • 918

QT 多线程信号与槽(二)

一个主线程,一个次线程,主线程向次线程发送信号 mythread.h #include #include class Mythread : public QThread { ...
  • u010646276
  • u010646276
  • 2014年01月03日 16:31
  • 863

Qt之信号signals和槽slots详解

目录(?)[-] 一概述 二信号 四信号和槽的关联 五元对象工具 六程式样例 七应注意的问题 8信号和槽也不能携带模板类参数 9嵌套的类不能位于信号或槽区域内也不能有信号或槽 10友元声明不能位...
  • Bruce_0712
  • Bruce_0712
  • 2016年12月16日 16:02
  • 4539
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Qt 信号与槽研究2
举报原因:
原因补充:

(最多只允许输入30个字)