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)
至此,路径分析就算清楚了。



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

相关文章推荐

关于Qt信号与槽机制的传递方向性研究

本文通过代码示例,论述了Qt中的信号与槽机制进行两对象通信时的工作模式问题

QT的信号与槽机制介绍(2)

四、信号与槽的关联 通过调用QObject对象的connect函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用。该函数的定义如下: bool QO...

Qt_log2000_信号与槽中的connect函数之深入part2

Qt学习记录6 (5’) Qt; C++ 11; Qt父子窗体; Qt父子窗体间信息传递; Qt信号与槽; 函数指针; 学习Qt将近2个月了,现在对学习所得进行记录。本文是log2000计划的一部...

QT布局,信号和槽PPT

  • 2014-03-20 08:42
  • 383KB
  • 下载

解读QT信号与槽机制里 QMetaObject::connectSlotsByName(QObject *o)的源码

解读QT信号与槽机制里 QMetaObject::connectSlotsByName(QObject *o)的源码 connectSlotsByName 是一个QMetaObject类里的stat...

【QT】信号槽初实现

  • 2015-09-21 13:48
  • 7.60MB
  • 下载

QT的信号与槽机制介绍

  • 2012-12-23 20:51
  • 14KB
  • 下载

QT5(4)代码实现应用及信号槽实例

一、基于Qt5的代码除了使用Qt的《设计》来快速添加控件,同样可以使用代码来添加控件。二、新建项目在新建项目过程中时取消创建界面,Qt将不会帮我们创建UI代码,需要我们手工添加。 三、添加代码1、在...

QT信号和槽机制分析.doc

  • 2016-09-25 15:30
  • 121KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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