簡體   English   中英

為什么 QProgressDialog 總是在應用程序啟動時顯示?

[英]Why is QProgressDialog always showing at app startup?

在 PyQt GUI 中,我將有幾個工作人員(與 QThread 關聯的 QObject),每個工作人員有 1 個 QProgressDialog。 每個人的壽命可能與另一個不同。

我天真地做了下面的例子,我在 GUI初始化時創建了所有必要的 QProgressDialog。

然而,每個在初始化時定義的 QProgressDialog 都會在啟動時顯示,即使我明確地將可見性設置為 False。 我多次嘗試使用 QProgressDialog,似乎工作版本都是基於每次我們需要它時創建的QProgressDialog 實例。

為什么 QProgressDialog 在啟動時顯示? 即時實例化是否更可取? (我不是在尋找意見,而是來自 Qt 代碼或 Qt 文檔的正式元素我可能錯過了)

處理進度對話框/進度條管理有各種問題,但似乎都沒有解決我的問題。 PyQt QProgressDialog 文檔對此沒有任何解釋, QDialog 文檔也沒有。


MCVE:

import sys
import time
from PyQt5.QtCore import QThread, Qt, QObject, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QMainWindow, QProgressDialog, QPushButton)


class WorkerA(QObject):
    finished = pyqtSignal()
    def do_it(self):
        time.sleep(5)
        self.finished.emit()


class Window(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setMinimumSize(250, 250)

        self.button = QPushButton(self)
        self.button.setText("Start worker A")
        self.button.clicked.connect(self.start_worker_A)

        self.thread_A = QThread()
        self.thread_A.setObjectName("ThreadA")
        self.worker_A = WorkerA()

        self.progress_dialog_A = QProgressDialog("Work A in progress", None, 0, 0, self)
        self.progress_dialog_A.setWindowModality(Qt.ApplicationModal)
        self.progress_dialog_A.setCancelButton(None)
        self.progress_dialog_A.setWindowTitle("Work A")
        self.progress_dialog_A.setVisible(False)
        self.progress_dialog_A.hide()

        self.thread_B = QThread()
        self.thread_B.setObjectName("ThreadB")
        self.worker_B = None

        self.progress_dialog_B = QProgressDialog("Work B in progress", None, 0, 0, self)
        self.progress_dialog_B.setWindowModality(Qt.ApplicationModal)
        self.progress_dialog_B.setCancelButton(None)
        self.progress_dialog_B.setWindowTitle("Work B")
        self.progress_dialog_B.setVisible(False)
        self.progress_dialog_B.hide()

    def start_worker_A(self):
        if not self.thread_A.isRunning():
            self.button.setEnabled(False)

            self.worker_A.moveToThread(self.thread_A)
            self.thread_A.started.connect(self.worker_A.do_it)
            self.thread_A.started.connect(self.progress_dialog_A.show)
            self.worker_A.finished.connect(self.thread_A.quit)
            self.worker_A.finished.connect(self.progress_dialog_A.hide)
            self.worker_A.finished.connect(self.enable_button)
            self.thread_A.start()
        else:
            pass

    def enable_button(self):
        self.button.setEnabled(True)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec())

上面的代碼總是在應用程序啟動時顯示 QProgressDialog,即使它們的可見性從未被顯式調用。


我嘗試了以下變體,效果很好,但我不明白 QProgressDialog 的生命周期邏輯。

class Window(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setMinimumSize(250, 250)

        self.button = QPushButton(self)
        self.button.setText("Start worker A")
        self.button.clicked.connect(self.start_worker_A)

        self.thread_A = QThread()
        self.thread_A.setObjectName("ThreadA")
        self.worker_A = WorkerA()

        self.progress_dialog_A : QProgressDialog = None
        # obviously no further operations here on self.progress_dialog_A
        # rest of init as first code sample above

    def start_worker_A(self):
        if not self.thread_A.isRunning():
            self.button.setEnabled(False)
            # QProgressDialog instantiated only when needed
            # any previous reference to QProgressDialog is garbaged collected ?
            # and a new instance created on the fly
            self.progress_dialog_A = QProgressDialog("Work A in progress", None, 0, 0, self)
            self.progress_dialog_A.setWindowModality(Qt.ApplicationModal)
            self.progress_dialog_A.setCancelButton(None)
            self.progress_dialog_A.setWindowTitle("Work A")
            self.progress_dialog_A.setVisible(False)
            self.progress_dialog_A.hide()

            self.worker_A.moveToThread(self.thread_A)
            self.thread_A.started.connect(self.worker_A.do_it)
            self.thread_A.started.connect(self.progress_dialog_A.show)
            self.worker_A.finished.connect(self.thread_A.quit)
            self.worker_A.finished.connect(self.progress_dialog_A.hide)
            self.worker_A.finished.connect(self.enable_button)
            self.thread_A.start()
        else:
            pass
# rest of code unchanged

我還嘗試覆蓋默認的 window show() 但沒有成功:

def show(self):
    super(Window, self).show()
    self.progress_dialog_A.hide()
    self.progress_dialog_B.hide()

這是預期的行為,雖然一開始可能不是很清楚,但在文檔中對此進行了解釋。

詳細描述

它估計操作將花費的時間(基於步驟的時間),並且僅在該估計超出 minimumDuration() 時顯示自身

然后, minimumDuration()

此屬性保存對話框出現之前必須經過的時間。

如果任務的預期持續時間小於 minimumDuration,則對話框根本不會出現。 這可以防止為快速結束的任務彈出對話框。 對於預期超過 minimumDuration 的任務,對話框將在 minimumDuration 時間后或設置任何進度后立即彈出。

如果設置為 0,則在設置任何進度后始終顯示對話框。 默認值為 4000 毫秒。

這是通過內部 QTimer 實現的,該 QTimer 在給定的minimumDuration() (默認為 4 秒)超時后立即調用forceShow() )。

一種可能的解決方案是在創建對話實例后立即停止計時器:

self.progress_dialog_A.findChild(QTimer).stop()
self.progress_dialog_B.findChild(QTimer).stop()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM