Объединение цикла событий ZMQ с циклом событий QT / Pyforms
Я пытаюсь реализовать как zmq, так и графический интерфейс Pyforms, для которого требуется собственный цикл обработки событий. Задача состоит в том, чтобы иметь графический интерфейс Pyforms с текстовым полем, которое отображает входящие сообщения 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
Второй вариант - добавить вызов функции zmq echo() в цикл событий Pyforms (который, насколько я знаю, основан на QT). Это может быть самым элегантным, но я не знаю, как реализовать или добавить что-то в цикл событий GUI.
Я много пробовал для обоих решений, но безуспешно.
Самая ценная информация, которую я смог найти здесь:
У меня не так много опыта, и я пытаюсь понять такие вещи, как фьючерсы, обещания и сопрограммы, но также и фреймворки, такие как asyncio, зеленые в python, но пока безуспешно. Я ищу простой вызов функции "echo", как только получено сообщение.
Есть идеи, как заставить это работать? Я делаю что-то глупое?
2 ответа
Заранее извиняюсь за неопределенный ответ, но, возможно, это может послужить потенциальной отправной точкой.
PyForms выглядит, в конечном счете, как основанный на Qt. Qt Я думаю, можно использовать сокет (ну, дескриптор файла) в качестве источника ввода. ZeroMQ, по крайней мере, версия C, предоставляет файловый дескриптор, который становится готовым для чтения после получения сообщения ZMQ. Таким образом, в принципе, Qt может использовать этот файловый дескриптор для вызова обратного вызова, который читает любой сокет ZMQ, получивший сообщение, и обрабатывает сообщение в потоке цикла событий Qt (что может иметь другие преимущества!).
Боюсь, я не знаю, разоблачено ли что-нибудь из этого PyZMQ и PyForms.
Спасибо Базза за ваш вклад. Ваш ответ помог мне найти решение моей проблемы. После поиска, как я могу испустить 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()
Большое спасибо и наилучшие пожелания!!!