赞
踩
资料:
https://github.com/PyQt5/PyQt/tree/master/QtRemoteObjects
https://github.com/PyQt5/PyQt/blob/master/QtRemoteObjects/simpleswitch/directconnectdynamicclient.py
由于项目要求,需要在python程序与c++程序之间通讯。经过取舍,觉得还是直接用QtRemoteObjects来实现这个通讯会比较合适。
QtRemoteObjects(以下简称QtRO)是一个qt的用于进程间通讯的模块。用QtRO通讯的两个进程(程序)可以在同一台电脑上,也可以在不同的电脑上(不同的电脑时,只需要在QRemoteObjectHost的url上修改一下就行)。
QtRO本质上是基于TCP/IP(可能也用到UDP?)实现的一个通讯协议,他可以让两个不同的进程(程序)也能享受到Qt的信号-槽机制,极大地减低了通讯成本。
关于QtRO的服务端与客户端的C++的实现可以参考这位大神写的介绍, 这里就不做赘述了。
这里主要介绍在python与c++之间的实现(这里是简单实现了一些功能,复杂的可以自行实现)
在python端,我们定义一个类,这个类包含了一个信号和一个槽。
RootComObj.py:
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, pyqtProperty from PyQt5.QtCore import QVariant class RootComObj(QObject): def __init__(self): super().__init__() # 用来发送信息到C++那边去,主要是告知此时的状态 serverToClient = pyqtSignal(QVariant) # 这个是供c++那边直接调用的槽函数,可以用来设置参数,也可以通过返回值读取参数。 # 这里只是提供基础的数据通讯,复杂的通讯可以在这个基础上实现自己的封装 # The slot exposed to a remote client. @pyqtSlot(QVariant, result=QVariant) def clientToServer(self, cmd): return cmd
使用PySide2的版本:
from PySide2.QtCore import QObject, Slot, Signal class RootComObj(QObject): def __init__(self): super().__init__() # 用来发送信息到C++那边去,主要是告知此时的状态 serverToClient = Signal("QVariant") # 这个是供c++那边直接调用的槽函数,可以用来设置参数,也可以通过返回值读取参数。 # 这里只是提供基础的数据通讯,复杂的通讯可以在这个基础上实现自己的封装 # The slot exposed to a remote client. @Slot("QVariant", result="QVariant") def clientToServer(self, cmd): print("c to s:", cmd) return cmd
main.py:
import sys import PyQt5.QtCore from PyQt5.QtCore import QUrl, QTimer, QDateTime from PyQt5.QtWidgets import QApplication from PyQt5.QtRemoteObjects import QRemoteObjectHost, QRemoteObjectNode from RootComObj import RootComObj comObj = RootComObj() def timeout(): comObj.serverToClient.emit(QDateTime.currentDateTime().toString('yyyyMMdd hh:mm:ss')) def main(): app = QApplication(sys.argv) remoteHost = QRemoteObjectHost(QUrl("local:replica")) ret = remoteHost.enableRemoting(comObj, 'demo') print(remoteHost, ret, PyQt5.QtCore.PYQT_VERSION_STR) tm = QTimer() tm.setInterval(1000) tm.setSingleShot(False) tm.timeout.connect(timeout) tm.start() return app.exec() if __name__ == '__main__': main()
使用PySide2的版本:
import PySide2.QtCore from PySide2.QtCore import QUrl, QTimer, QDateTime, QVariantAnimation from PySide2.QtWidgets import QApplication from PySide2.QtRemoteObjects import QRemoteObjectHost, QRemoteObjectNode from RootComObj import RootComObj comObj = RootComObj() def main(): app = QApplication(sys.argv) remoteHost = QRemoteObjectHost(QUrl("local:replica")) ret = remoteHost.enableRemoting(comObj, 'demo') return app.exec_()
接着,C++这边采用的是动态Replica的方式(实际上静态也行,只要你写对那个rep文件就行)
Receiver.h
class Receiver: public QObject
{
Q_OBJECT
public:
Receiver()
{
}
public slots:
void processServerCmd(QVariant cmd)
{
qDebug() << "the server cmd is:" << cmd;
}
};
main.cpp:
#include "mainwindow.h" #include "Receiver.h" #include <QApplication> #include <QDebug> int main(int argc, char *argv[]) { QApplication a(argc, argv); //MainWindow w; //w.show(); Receiver *rev = new Receiver(); QRemoteObjectNode repNode; // create remote object node repNode.connectToNode(QUrl("local:replica")); // connect with remote host node auto rep = repNode.acquireDynamic("demo"); QObject::connect(rep, &QRemoteObjectReplica::stateChanged, [=](QRemoteObjectReplica::State sta, QRemoteObjectReplica::State oldSta){ qDebug() << "oldState:" << oldSta; qDebug() << "state:" << sta; }); //动态replica要等初始化完成之后(也就是连接上服务器+内部初始化完成)才能做信号槽的连接,静态就无所谓 QObject::connect(rep, &QRemoteObjectReplica::initialized, [=](){ // 可以利用Qt的反射机制输出一些东西看看 // auto obj = rep->metaObject(); // for(int i = 0; i < obj->methodCount(); i++) // { // auto method = obj->method(i); // qDebug() << method.name() << method.tag() << method.typeName() << method.methodType(); // for(int j = 0; j < method.parameterCount(); j++) // { // qDebug() << "---" << method.parameterType(j) << method.parameterNames() << method.parameterTypes(); // } // } // 获取属性 // qDebug() << "initialized:" << rep->property("currState"); // 连接信号, 动态replica的话,连接信号就不能用lambda表达式了,需要这样直接指明信号槽字符串 QObject::connect(rep, SIGNAL(serverToClient(QVariant)), rev, SLOT(processServerCmd(QVariant))); // clientToServer的返回值并不直接是我们指定的类型,而是返回一个类似操作器的东西,通过这个东西我们再取得返回值。 QRemoteObjectPendingCall val; // 执行槽函数 QMetaObject::invokeMethod(rep, "clientToServer", Qt::DirectConnection, Q_RETURN_ARG(QRemoteObjectPendingCall, val), Q_ARG(QVariant, "sdfdsfdf")); val.waitForFinished(); qDebug() << "return:" << val.returnValue(); }); return a.exec(); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。