在PyQt的应用程序时,我尝试从一个长期运行的singleShot任务,他们没有得到rendred显示对话框窗口

问题描述 投票:0回答:2

我有一个运行很长的任务命令行应用程序。我目前想的用户界面添加到它,我使用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()
python qt pyqt pyqt5
2个回答
2
投票

你的工人功能块整个事件循环,这就是为什么你没有看到任何提示信息。 要执行长时间运行的功能,最好是将其移动到一个新的线程。在QT,线程不允许访问窗口小部件,所以你需要使用的线程之间的信号来工作,使主线程显示的对话框中,你想。

你会看到对话框中,持续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
投票

您需要的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()
© www.soinside.com 2019 - 2024. All rights reserved.