将ZMQ事件循环与QT / Pyforms事件循环相结合

问题描述 投票:2回答:2

我正在尝试实现zmq和Pyforms GUI,它们都需要自己的事件循环。任务是使用带有文本字段的Pyforms GUI,显示传入的zmq消息。这是我试图开始工作的简化代码。

import pyforms
from   pyforms          import BaseWidget
from   pyforms.controls import ControlTextArea
from   pyforms.controls import ControlButton
import threading
import zmq
from zmq.asyncio import Context
from zmq.eventloop.zmqstream import ZMQStream
from zmq.eventloop import ioloop


class SimpleExample1(BaseWidget):

    def __init__(self):
        super(SimpleExample1,self).__init__('Simple example 1')

        #Definition of the forms fields
        self._controltextarea     = ControlTextArea('textarea to show incoming zmq messages')
        self._button        = ControlButton('Press this button')

        def echo(msg):
            self._controltextarea.__add__(msg) #this should add a line in the Textbox with the message "msg"


        context = Context.instance()
        s = context.socket(zmq.PULL)
        s.connect('tcp://127.0.0.1:5014')
        stream = ZMQStream(s)
        stream.on_recv(echo)  #this calls the function echo from the zmq Ioloop when something is recived

#Execute the application
if __name__ == "__main__":
    #here is where I have tried a lot to make both loops work simultaniously, without success
    guiThread = threading.Thread(target=pyforms.start_app( SimpleExample1 ))
    zmqThread = threading.Thread(target=lambda: ioloop.IOLoop.current().start())
    zmqThread.setDaemon(True)
    guiThread.start()
    zmqThread.start()

这是ZMQ发件人。

import zmq
import time

context = zmq.Context()
publisher = context.socket(zmq.PUSH)
publisher.bind('tcp://127.0.0.1:5014')

while True:
    publisher.send_string('something')
    #print('sended')
    time.sleep(1)

我看到2种可能的解决方案首先它可以使用上面代码中的线程。但我还没有找到启动这两个事件循环的方法。当我不使用lamda等时,一个语句阻止另一个语句或者我收到错误消息。或者它只是不起作用。 - 这是我试图为此实现的参考没有成功,描述了类似的任务:github maartenbreddels

第二个选项是将echo()的zmq函数调用添加到Pyforms的事件循环中(据我所知,它基于QT)。这可能是最优雅的,但我不知道如何实现或添加GUI的事件循环。

我为这两种解决方案做了很多努力而没有成功。 我能找到的最有价值的信息是:

pyzmq readthedocs

zeromq org

pyforms readthedocs

我没有很多经验,并且尝试理解诸如期货,承诺和协同程序之类的东西,但是到目前为止还没有成功的框架如asyncio,green in python。一旦收到消息,一个简单的函数调用“echo”就是我正在寻找的。

任何想法如何使其工作?我做傻事吗?

python event-handling zeromq pyforms
2个回答
0
投票

提前道歉的是一个模糊的答案,但也许它可以作为一个潜在的起点。

PyForms最终看起来像是基于Qt。我认为可以使用套接字(好吧,文件描述符)作为输入偶数源。 ZeroMQ,至少是C版本,公开了一个文件描述符,当收到ZMQ消息时,该文件描述符变为准备读取。所以原则上,Qt可以使用这个文件描述符来调用一个回调来读取ZMQ套接字收到的消息,并在Qt事件循环的线程上处理消息(这可能有其他好处!)。

PyZMQ和PyForms是否暴露了这些,恐怕我不知道。


0
投票

感谢Bazza的意见。你的回答帮助我找到解决问题的方法。在搜索了我如何发射Qevent之后;我找到了以下示例example并解决了这个问题。最终代码如下所示:

import pyforms
from   pyforms          import BaseWidget
from   pyforms.controls import ControlTextArea
from   pyforms.controls import ControlButton
import threading
import zmq
from PyQt5 import QtCore

class ZeroMQ_Listener(QtCore.QObject):

    message = QtCore.pyqtSignal(str)

    def __init__(self):

        QtCore.QObject.__init__(self)

        # Socket to talk to server
        context = zmq.Context()
        self.socket = context.socket(zmq.PULL)
        self.socket.connect('tcp://127.0.0.1:5014')
        print('connected!')
        self.running = True

    def loop(self):
        while self.running:
            string = self.socket.recv_string()
            self.message.emit(string)


class SimpleExample1(BaseWidget):

    def __init__(self):
        super(SimpleExample1,self).__init__('Simple example 1')

        #Definition of the forms fields
        self._controltextarea     = ControlTextArea('textarea to show incoming zmq messages')
        self._button        = ControlButton('Press this button')

        message = QtCore.pyqtSignal(str)
        self.thread = QtCore.QThread()
        self.zeromq_listener = ZeroMQ_Listener()

        self.zeromq_listener.moveToThread(self.thread)

        self.thread.started.connect(self.zeromq_listener.loop)
        self.zeromq_listener.message.connect(self.signal_received)

        QtCore.QTimer.singleShot(0, self.thread.start)


    def signal_received(self, message):
        self._controltextarea.__add__(message)

#Execute the application
if __name__ == "__main__":
    guiThread = threading.Thread(target=pyforms.start_app( SimpleExample1 ))

    guiThread.start()

非常感谢和最好的问候!!!

© www.soinside.com 2019 - 2024. All rights reserved.