В приложении PyQt, когда я пытаюсь показать диалоговые окна из длительной задачи singleShot, они не получают сотни - PullRequest
0 голосов
/ 01 февраля 2019

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

Итак, я делаю следующее: сначала я создаю QApplication, затем создаюодиночный снимок QTimer, который затем выполняет долгосрочную задачу, а затем я запускаю exec() метод приложения.Внутри длительной задачи я пытаюсь вызвать методы диалоговых окон show() и hide(), но окна не отображаются должным образом и просто отображаются черным (по крайней мере, в Ubuntu 18.04).

Если я вызываю exec() метод диалогового окна из длительной задачи, диалог отображается правильно, но это, конечно, блокирует задачу, пока окно не будет закрыто.

Есть ли способ сделатьэто работает, не блокируя долго выполняющуюся задачу?

См. код ниже для минимального нерабочего примера:

#!/usr/bin/env python3


import sys
import time

from PyQt5 import QtCore, QtWidgets


class Dialog(QtWidgets.QDialog):
    """Dialog window with just a text label."""

    def __init__(self, text, parent=None):
        self.text = text
        super().__init__(parent)
        self.setupUi()

    def setupUi(self):
        self.layout = QtWidgets.QVBoxLayout()
        self.label = QtWidgets.QLabel(self.text)

        self.setLayout(self.layout)
        self.layout.addWidget(self.label)


class Application(QtWidgets.QApplication):
    """An example QApplication launching the worker function."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.root = Dialog("Root window")
        self.dialog_a = Dialog("Dialog A")
        self.dialog_b = Dialog("Dialog B")

    def show_a(self):
        self.dialog_b.hide()
        self.dialog_a.show()

    def show_b(self):
        self.dialog_a.hide()
        self.dialog_b.show()

    def exec(self):
        QtCore.QTimer.singleShot(0, lambda: worker(self))
        super().exec()


def worker(app):
    """
    This is the main worker function that should occasionaly ask
    Application to show different dialog windows.  Unfortunately the
    windows do not get rendered until the worker function is done.
    """

    app.show_a()
    for _ in range(10):
        time.sleep(0.5)
        print(".")

    app.show_b()
    for _ in range(10):
        time.sleep(0.5)
        print(".")


app = Application([])
app.exec()

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

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

Вы увидите диалог A в течение 5 секунд, покаПотоки записывают в стандартный вывод, после того, как показано диалоговое окно B:

import sys
import time

from PyQt5 import QtWidgets
from PyQt5.QtCore import QCoreApplication, Qt, QThread, QObject, pyqtSignal, pyqtSlot, QTimer


class Dialog(QtWidgets.QDialog):
    """Dialog window with just a text label."""

    def __init__(self, text, parent=None):
        self.text = text
        super().__init__(parent)
        self.setupUi()

    def setupUi(self):
        self.layout = QtWidgets.QVBoxLayout()
        self.label = QtWidgets.QLabel(self.text)

        self.setLayout(self.layout)
        self.layout.addWidget(self.label)


class Application(QtWidgets.QApplication):
    """An example QApplication launching the worker function."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._threads = []

        self.root = Dialog("Root window")
        self.dialog_a = Dialog("Dialog A")
        self.dialog_b = Dialog("Dialog B")

        self.dialog_a.hide()
        self.dialog_b.hide()

        worker = Worker()
        wThread = QThread()
        wThread.setObjectName('worker')
        self._threads.append((wThread, worker))  # you need to keep track of the threads and instances.
        worker.moveToThread(wThread)
        worker.showDialog.connect(self._switchDialog)  # connect the signal from the thread to a function to show/hide the dialogs.
        wThread.started.connect(worker.start)
        wThread.start()

    def _switchDialog(self, dialogId):
        if dialogId == 'a':
            self.show_a()
        else:
            self.show_b()

    def show_a(self):
        self.dialog_b.hide()
        self.dialog_a.show()

    def show_b(self):
        self.dialog_a.hide()
        self.dialog_b.show()



class Worker(QObject):
    showDialog = pyqtSignal(str)

    """
    This is the main worker function that should occasionaly ask
    Application to show different dialog windows.  Unfortunately the
    windows do not get rendered until the worker function is done.
    """
    def __init__(self):
        super().__init__()
        print('setup worker')

    @pyqtSlot()
    def start(self):
        self.timer = QTimer()
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.run)
        self.timer.start()

    def run(self):
        for dialog in ('a', 'b'):
            print ("showing dialog: %s" % dialog)
            self.showDialog.emit(dialog)
            for _ in range(10):
                time.sleep(0.5)
                print(".")

app = Application([])
sys.exit(app.exec_())

Примечание. В общем, так оно и работает, я старался сохранить большую часть кода.Пожалуйста, просмотрите некоторые учебники по PyQt для получения дополнительной информации.

0 голосов
/ 01 февраля 2019

Вам нужен метод QApplication.processEvents () :

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.root = Dialog("Root window")
    self.dialog_a = Dialog("Dialog A", parent=self.root)
    self.dialog_b = Dialog("Dialog B", parent=self.root)

def show_a(self):
    self.dialog_b.hide()
    self.dialog_a.show()
    self.processEvents()

def show_b(self):
    self.dialog_a.hide()
    self.dialog_b.show()
    self.processEvents()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...