Объединение цикла событий 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.

Я много пробовал для обоих решений, но безуспешно.
Самая ценная информация, которую я смог найти здесь:

pyzmq readthedocs

Zeromq org

Pyforms readthedocs

У меня не так много опыта, и я пытаюсь понять такие вещи, как фьючерсы, обещания и сопрограммы, но также и фреймворки, такие как 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()

Большое спасибо и наилучшие пожелания!!!

Другие вопросы по тегам