Как сигнализировать слоты в графическом интерфейсе из другого процесса?

Контекст. В Python основной поток генерирует второй процесс (используя модуль многопроцессорности), а затем запускает графический интерфейс (используя PyQt4). В этот момент основной поток блокируется до закрытия GUI. Второй процесс всегда обрабатывается и в идеале должен излучать сигнал (ы) в определенный слот (ы) в графическом интерфейсе асинхронным образом.

Вопрос: Какой подход / инструменты доступны в Python и PyQt4 для достижения этого и как? Предпочтительно, с мягким прерыванием, а не с опросом.

В частности, решение, о котором я могу думать, это «инструмент / обработчик», созданный в основном потоке, который захватывает доступные слоты из экземпляра GUI и соединяется с захваченными сигналами второго процесса, предполагая, что я предоставляю этому инструменту некоторую информацию о том, что ожидать или жестко закодировать. Это может быть создано для третьего процесса / потока.

4 Solutions collect form web for “Как сигнализировать слоты в графическом интерфейсе из другого процесса?”

Это пример приложения Qt, показывающий отправку сигналов от дочернего процесса в слоты в процессе материнской линии. Я не уверен, что это правильный подход, но он работает.

Я различаю процесс как мать и ребенок , потому что слово parent is alread используется в контексте Qt.
Маточный процесс имеет два потока. Основной поток материнского процесса отправляет данные дочернему процессу через multiprocessing.Queue . multiprocessing.Queue . Детский процесс отправляет обработанные данные и подпись сигнала, который должен быть отправлен во второй поток материнского процесса через multiprocessing.Pipe . Второй поток материнского процесса фактически излучает сигнал.

Python 2.X, PyQt4:

 from multiprocessing import Process, Queue, Pipe from threading import Thread import sys from PyQt4.QtCore import * from PyQt4.QtGui import * class Emitter(QObject, Thread): def __init__(self, transport, parent=None): QObject.__init__(self,parent) Thread.__init__(self) self.transport = transport def _emit(self, signature, args=None): if args: self.emit(SIGNAL(signature), args) else: self.emit(SIGNAL(signature)) def run(self): while True: try: signature = self.transport.recv() except EOFError: break else: self._emit(*signature) class Form(QDialog): def __init__(self, queue, emitter, parent=None): super(Form,self).__init__(parent) self.data_to_child = queue self.emitter = emitter self.emitter.daemon = True self.emitter.start() self.browser = QTextBrowser() self.lineedit = QLineEdit('Type text and press <Enter>') self.lineedit.selectAll() layout = QVBoxLayout() layout.addWidget(self.browser) layout.addWidget(self.lineedit) self.setLayout(layout) self.lineedit.setFocus() self.setWindowTitle('Upper') self.connect(self.lineedit,SIGNAL('returnPressed()'),self.to_child) self.connect(self.emitter,SIGNAL('data(PyQt_PyObject)'), self.updateUI) def to_child(self): self.data_to_child.put(unicode(self.lineedit.text())) self.lineedit.clear() def updateUI(self, text): text = text[0] self.browser.append(text) class ChildProc(Process): def __init__(self, transport, queue, daemon=True): Process.__init__(self) self.daemon = daemon self.transport = transport self.data_from_mother = queue def emit_to_mother(self, signature, args=None): signature = (signature, ) if args: signature += (args, ) self.transport.send(signature) def run(self): while True: text = self.data_from_mother.get() self.emit_to_mother('data(PyQt_PyObject)', (text.upper(),)) if __name__ == '__main__': app = QApplication(sys.argv) mother_pipe, child_pipe = Pipe() queue = Queue() emitter = Emitter(mother_pipe) form = Form(queue, emitter) ChildProc(child_pipe, queue).start() form.show() app.exec_() 

И как удобство также Python 3.X, PySide:

 from multiprocessing import Process, Queue, Pipe from threading import Thread from PySide import QtGui, QtCore class Emitter(QtCore.QObject, Thread): def __init__(self, transport, parent=None): QtCore.QObject.__init__(self, parent) Thread.__init__(self) self.transport = transport def _emit(self, signature, args=None): if args: self.emit(QtCore.SIGNAL(signature), args) else: self.emit(QtCore.SIGNAL(signature)) def run(self): while True: try: signature = self.transport.recv() except EOFError: break else: self._emit(*signature) class Form(QtGui.QDialog): def __init__(self, queue, emitter, parent=None): super().__init__(parent) self.data_to_child = queue self.emitter = emitter self.emitter.daemon = True self.emitter.start() self.browser = QtGui.QTextBrowser() self.lineedit = QtGui.QLineEdit('Type text and press <Enter>') self.lineedit.selectAll() layout = QtGui.QVBoxLayout() layout.addWidget(self.browser) layout.addWidget(self.lineedit) self.setLayout(layout) self.lineedit.setFocus() self.setWindowTitle('Upper') self.lineedit.returnPressed.connect(self.to_child) self.connect(self.emitter, QtCore.SIGNAL('data(PyObject)'), self.updateUI) def to_child(self): self.data_to_child.put(self.lineedit.text()) self.lineedit.clear() def updateUI(self, text): self.browser.append(text[0]) class ChildProc(Process): def __init__(self, transport, queue, daemon=True): Process.__init__(self) self.daemon = daemon self.transport = transport self.data_from_mother = queue def emit_to_mother(self, signature, args=None): signature = (signature, ) if args: signature += (args, ) self.transport.send(signature) def run(self): while True: text = self.data_from_mother.get() self.emit_to_mother('data(PyQt_PyObject)', (text.upper(),)) if __name__ == '__main__': app = QApplication(sys.argv) mother_pipe, child_pipe = Pipe() queue = Queue() emitter = Emitter(mother_pipe) form = Form(queue, emitter) ChildProc(child_pipe, queue).start() form.show() app.exec_() 

Сначала нужно посмотреть, как сигналы / слоты работают только в одном процессе Python:

Если есть только один запущенный QThread, они просто называют слоты напрямую.

Если сигнал испускается в другом потоке, он должен найти целевой поток сигнала и поместить сообщение / отправить событие в очередь потока этого потока. Затем этот поток будет в свое время обрабатывать сообщение / событие и вызывать сигнал.

Таким образом, внутри нас всегда есть какой-то опрос, и важно то, что опрос не блокирует.

Процессы, созданные многопроцессорной обработкой, могут связываться через Pipes, что дает вам два соединения для каждой стороны.

Функция poll Connection не блокирует, поэтому я бы регулярно проводил опрос с помощью QTimer и затем соответствующим образом излучал сигналы.

Другое решение может состоять в том, чтобы Thread из модуля потоковой передачи (или QThread) специально ожидал новых сообщений из Queue с функцией получения очереди. Дополнительную информацию см. В разделе «Трубы и очереди» для многопроцессорности .

Ниже приведен пример запуска Qt GUI в другом Process вместе с Thread который прослушивает Connection и по определенному сообщению закрывает GUI, который затем завершает процесс.

 from multiprocessing import Process, Pipe from threading import Thread import time from PySide import QtGui class MyProcess(Process): def __init__(self, child_conn): super().__init__() self.child_conn = child_conn def run(self): # start a qt application app = QtGui.QApplication([]) window = QtGui.QWidget() layout = QtGui.QVBoxLayout(window) button = QtGui.QPushButton('Test') button.clicked.connect(self.print_something) layout.addWidget(button) window.show() # start thread which listens on the child_connection t = Thread(target=self.listen, args = (app,)) t.start() app.exec_() # this will block this process until somebody calls app.quit def listen(self, app): while True: message = self.child_conn.recv() if message == 'stop now': app.quit() return def print_something(self): print("button pressed") if __name__ == '__main__': parent_conn, child_conn = Pipe() s = MyProcess(child_conn) s.start() time.sleep(5) parent_conn.send('stop now') s.join() 

Очень интересная тема. Я думаю, что сигнал, который работает между потоками, очень полезен. Как насчет создания пользовательского сигнала на основе сокетов? Я еще не проверял это, но это то, что я собрал с помощью быстрого расследования:

 class CrossThreadSignal(QObject): signal = pyqtSignal(object) def __init__(self, parent=None): super(QObject, self).__init__(parent) self.msgq = deque() self.read_sck, self.write_sck = socket.socketpair() self.notifier = QSocketNotifier( self.read_sck.fileno(), QtCore.QSocketNotifier.Read ) self.notifier.activated.connect(self.recv) def recv(self): self.read_sck.recv(1) self.signal.emit(self.msgq.popleft()) def input(self, message): self.msgq.append(message) self.write_sck.send('s') 

Может просто поставить вас на правильный путь.

У меня была такая же проблема в C ++. Из QApplication я создаю объект службы. Объект создает Gui Widget, но он не является его родителем (тогда родительский QApplication). Чтобы управлять GuiWidget из виджета службы, я просто использую сигналы и слоты, как обычно, и работает так, как ожидалось. Примечание: поток GuiWidget и один из сервисов различны. Служба является подклассом QObject.

Если вам нужен механизм многопроцессного сигнала / слота, попробуйте использовать Apache Thrift или используйте процесс контроля Qt, который создает 2 объекта QProcess.

  • проблема с отображением sympy rendered svg в python
  • Пакетное приложение PyInstaller отлично работает в режиме консоли, сбой в режиме окна
  • python / pyside с использованием настраиваемого виджета в qtreewidget
  • установка pyside с использованием PIP - nmake не найдена
  • Связь между потоками в PySide
  • Отображение видеопотока в QLabel с помощью PySide
  • Ошибка системного пути с PyQt и Py2exe
  • QLabel () не загружает pixmap, если это изображение в формате JPG
  •  
    Interesting Posts for Van-Lav

    Почему этот memoizer работает над рекурсивными функциями?

    Простая динамическая модель в PyMC3

    Сравнение производительности: вставка vs build Операции с наборами Python

    Как предотвратить конфликты приборов с конфликтом с сигнальным кодом django post_save?

    Tkinter и потоки

    OperationTimedOut: errors = {}, last_host = 127.0.0.1

    Что такое быстрый питонический способ глубокого копирования только данных из файла или списка python?

    Django South: как я могу получить доступ к моделям в подпакетах при миграции

    передача экземпляров классов C ++ в python с boost :: python

    сертификаты для клиентской стороны в tls

    Как определить, какой из атрибутов атрибута объекта терпит неудачу?

    Как создать обнаружение коллизий для моих прыгающих шаров?

    Почему python-cgi выходит из строя в юникоде?

    Получите доступ к содержимому массива из файла .mat, загруженного с помощью Scipy.io.loadmat – python

    Plone. Почему я получаю ошибку WrongContainedType?

    Python - лучший язык программирования в мире.