python - 将 ZMQ 事件循环与 QT / Pyforms 事件循环相结合
问题描述
我正在尝试同时实现 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)
我看到了两种可能的解决方案。首先,它可以与上面代码中的线程一起工作。但是我还没有找到一种方法来启动两个事件循环。当我不使用 lamda 等时,一个语句会阻塞另一个语句,或者我收到错误消息。或者它只是不工作。- 这是我尝试实现但没有成功的参考,描述了类似的任务:github maartenbreddels
第二种选择是将 echo() 的 zmq 函数调用添加到 Pyforms 的事件循环中(据我所知,它基于 QT)。这可能是最优雅的,但我不知道如何实现或添加一些东西到 GUI 的事件循环中。
我对这两种解决方案都进行了很多尝试,但都没有成功。
我能找到的最有价值的信息在这里:
我没有太多经验,并试图理解诸如期货、承诺和协程之类的东西,但也了解诸如 asyncio 之类的框架,到目前为止,python 中的绿色还没有成功。一旦收到消息,对“echo”的简单函数调用就是我正在寻找的。
任何想法如何使它工作?我在做傻事吗?
解决方案
谢谢巴扎的意见。您的回答帮助我找到了解决问题的方法。在搜索了如何发出 Qevent 之后;我找到了以下示例并解决了问题。最终代码如下所示:
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()
非常感谢和最好的问候!!!
推荐阅读
- c# - 如果两个 nuget 包指向同一个 Dll 怎么办
- c - 是否可以使用“touch”命令管理间接 .h 依赖项?
- java - 使用 Iterator 遍历 ArrayList 并使用 instanceof 设置对象
- php - Why does my PHP function prevent other code from working?
- r - 我怎样才能找到 (sqrt(1+x)-1)x 的泰勒级数?
- r - 选择数据集中的第一个、最后一个和单个观察值
- scala - 我可以从 scala-spark 的目录中只读取想要的文件吗
- google-drive-api - 如何获取google drive api文件夹中所有子文件夹中具有特定扩展名的所有文件的列表?
- azure-ad-b2c - 有没有办法从 url 设置 JwtIssuer id_token_lifetime_secs
- php - How to display background image using PHP/CSS