当前位置:   article > 正文

利用QtRemoteObjects在C++与Python之间通讯_qtremoteobject python c++

qtremoteobject python c++

资料:
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

使用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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

使用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_()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

接着,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;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号