Как запустить PyQt5 GUI в неблокирующих потоках? - PullRequest
0 голосов
/ 19 января 2019

У меня есть класс PyQt5 GUI, который я хочу иметь возможность создавать несколько экземпляров из интерактивной консоли или обычного запуска.Мне нужно, чтобы эти графические интерфейсы были неблокирующими, чтобы их можно было использовать во время выполнения следующего кода.

Я пытался вызывать app.exec __ () в отдельных потоках для каждого графического интерфейса, как этот ответ, но иногда программавылетает, когда комментарий к ответу предупреждает:
Запуск основного приложения pyQT GUI в отдельной теме

И теперь я пытаюсь получить приведенный ниже код, который я сделал на основена этот ответ:
Запуск основного приложения Pyqt GUI как отдельного неблокирующего процесса

Но когда я запускаю его, окна всплывают и сразу исчезают

import sys
from PyQt5 import QtWidgets, QtGui, QtCore
import time

class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        # call super class constructor
        super(MainWindow, self).__init__()
        # build the objects one by one
        layout = QtWidgets.QVBoxLayout(self)
        self.pb_load = QtWidgets.QPushButton('Load')
        self.pb_clear= QtWidgets.QPushButton('Clear')
        self.edit = QtWidgets.QTextEdit()
        layout.addWidget(self.edit)
        layout.addWidget(self.pb_load)
        layout.addWidget(self.pb_clear)
        # connect the callbacks to the push-buttons
        self.pb_load.clicked.connect(self.callback_pb_load)
        self.pb_clear.clicked.connect(self.callback_pb_clear)

    def callback_pb_load(self):
        self.edit.append('hello world')
    def callback_pb_clear(self):
        self.edit.clear()

def show():
    app = QtWidgets.QApplication.instance()
    if not app:
        app = QtWidgets.QApplication(sys.argv)
    win = MainWindow()
    win.show()

if __name__ == '__main__':
    show()
    show()

РЕДАКТИРОВАТЬ - Я не вижу, как этот вопрос является дубликатом.«Дублирующиеся» вопросы очень слабо связаны и совсем не дают решения моей проблемы.

Я хочу иметь возможность создавать несколько экземпляров GUI (MainWindow в моем примере), вызывая show () из интерактивного сеанса или скрипта, и я хочу, чтобы эти окна оставались на моем экране во время выполнения последующего кода.

EDIT2 - Когда я запускаю код как скрипт, я могу делать то, что хочу, используямногопроцессорная обработка, см. эту демонстрацию:
https://www.screencast.com/t/5WvJNVSLm9OR

Однако мне все еще нужна помощь, потому что я хочу, чтобы она также работала в интерактивных сеансах консоли Python, и многопроцессорная обработка в этом случае не работает.

Ответы [ 2 ]

0 голосов
/ 20 января 2019

В итоге я сделал это, используя многопроцессорность для запуска каждого экземпляра графического интерфейса в отдельном процессе, и использовал многопроцессный модуль pathos , чтобы он работал в интерактивном режиме

main.py

import time
import multiprocess

def start_gui():
    import sys
    from PyQt5 import QtWidgets

    # Set up QApplication
    app = QtWidgets.QApplication.instance()
    if not app:
        app = QtWidgets.QApplication(sys.argv)

    # Make GUi
    import gui
    win = gui.MainWindow()

    app.exec_()

def show():
    thread = multiprocess.Process(target=start_gui)
    thread.start()

if __name__ == '__main__':
    show()
    print('This happens now')
    show()

    # Task that takes 5 seconds
    time.sleep(5)

    print('This happens later')

gui.py

from PyQt5 import QtWidgets

class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        # call super class constructor
        super(MainWindow, self).__init__()
        # build the objects one by one
        layout = QtWidgets.QVBoxLayout(self)
        self.pb_load = QtWidgets.QPushButton('Load')
        self.pb_clear= QtWidgets.QPushButton('Clear')
        self.edit = QtWidgets.QTextEdit()
        layout.addWidget(self.edit)
        layout.addWidget(self.pb_load)
        layout.addWidget(self.pb_clear)
        # connect the callbacks to the push-buttons
        self.pb_load.clicked.connect(self.callback_pb_load)
        self.pb_clear.clicked.connect(self.callback_pb_clear)

        self.show()

    def callback_pb_load(self):
        self.edit.append('hello world')
    def callback_pb_clear(self):
        self.edit.clear()
0 голосов
/ 19 января 2019

Для этого не обязательно использовать отдельные потоки или процессы. Вам просто нужен способ сохранить ссылку на каждое новое окно при импорте сценария в интерактивном сеансе Python. Для этого можно использовать простой список. Необходимо только явно запустить цикл обработки событий при запуске сценария из командной строки; в интерактивном сеансе он будет автоматически обрабатываться PyQt.

Вот реализация этого подхода:

...
_cache = []

def show(title=''):
    if QtWidgets.QApplication.instance() is None:
        _cache.append(QtWidgets.QApplication(sys.argv))
    win = MainWindow()
    win.setWindowTitle(title)
    win.setAttribute(QtCore.Qt.WA_DeleteOnClose)
    win.destroyed.connect(lambda: _cache.remove(win))
    _cache.append(win)
    win.show()

if __name__ == '__main__':

    show('Foo')
    show('Bar')

    sys.exit(QtWidgets.QApplication.instance().exec_())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...