赞
踩
上一篇QtRO的文章(Qt Remote Objects 静态Replica)中我们介绍了它的静态用法,并给出了一个具体例子。这篇文章我给大家介绍动态Replica,即Dynamic Replica。
要支持动态Replica,Server端其实不需要做太大更改,主要流程和静态Replica一致。但需要注意:
在定义rep接口文件时,禁用POD。换句话说,所有的数据类型必须是基本类型(即float、int等基本C++类型,还有QString、QPoint等基本Qt类型)。QtRO中的POD类型依赖于QDataStream的序列化和反序列化,这些都需要Qt元信息的支持。而动态Replica那边没有了rep文件,也就没有了对POD的反序列化能力,换句话说就是它不认识收到的POD二进制数据了。
如果Server端确实需要传输复杂的数据类型(这个在接口复杂的时候是个刚需),那我建议用QVariantList
和QVariantMap
来定义。虽然传输性能上差一些,但是在提供更好的数据封装的情况下仍然保持了好的QtRO编程习惯。
所以,现在我们的TransferNews例子的Server端唯一改变的是在transfernews.cpp中的注释掉下面这行代码:
//emit testPod(Foo(list));
Source端算是准备好了。
采用动态方式的话,Replica端变化相对较多。
首先是pro文件中不再需要引入rep文件。所以去掉下面这行代码:
REPC_REPLICA = transfernews.rep
然后在获得Replica的时候,需要用动态的版本:
ptr.reset(repNode.acquireDynamic("TransferNews"));
此时,如果我们运行Replica端程序,会发现下面的错误:
- QObject::connect: No such signal QRemoteObjectReplica::lastMessageChanged(QString)
- QObject::connect: No such signal QRemoteObjectReplica::serverTime(QString)
这是因为我们在dynamicconnect.cpp里将replica
的信号连接到本地的槽函数上,而此时动态replica
其实还未初始化好,也就是说它根本没有这些信号。这就引出动态Replica的一个重要特点:
只有当Replica发出initialized
信号后,该Replica才有Server端的元信息(属性、信号与槽),才能被使用。
仔细想想就能明白为什么。因为没了rep文件,程序刚启动时怎么可能知道你要连接的Server端长啥样。所以动态Replica的内部原理是建立连接后,首先获得Server端的元信息,然后动态地在Replica端构建属性、信号和槽。这些构造完毕后,Replica会发送一个initialized
的信号,这之后该Replica才能够真正被使用。
所以,我们要确保的就是只有Replica初始化好了我们才在widget中使用该Replica进行信号绑定等操作。解决方法也很简单,在dynamicconnect.cpp中用下面的代码来绑定:
- QObject::connect(ptr.data(), SIGNAL(initialized()), this, SLOT(initConnection()));
-
- void DynamicConnect::initConnection()
- {
- QObject::connect(m_ptr.data(), SIGNAL(lastMessageChanged(QString)), this, SLOT(slot_lastMessageChanged(QString)));
- QObject::connect(m_ptr.data(), SIGNAL(serverTime(QString)), this, SLOT(slot_serverTimeChanged(QString)));
- }
再运行Replica端程序,发现上面的错误消失了,运行结果和之前的静态方式一致。
当然,上面的代码应该是最简单的形式。
QVariantList
和QVariantMap
两兄弟来曲线救国。相信看了这个比较后,应该知道怎么选择了吧?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。