PyQt5中使用QThread显示QProgressDialog

Using QThread to display QProgressDialog in PyQt5

我正在使用 PyQt5 编写一个管理销售订单的应用程序。创建或删除订单时,我想显示一个字幕样式的进度对话框以指示该应用程序正在运行。我访问了很多帖子,其中涉及使用 QThread.I 的答案试图实现它,但似乎我遗漏了一些东西。这是我的线程 class.

class Worker(QThread):
    finished = Signal()

def run(self):
    self.x = QProgressDialog("Please wait..",None,0,0)
    self.x.show()

def stop(self):
    self.x.close()

在 Main window 的 init 我创建 self.worker=Worker()

现在删除条目的代码例如:

msg = MsgBox("yn", "Delete Order", "Are you sure you want to delete this order?") # Wrapper for the QMessageBox
if msg == 16384:
    self.worker.start()   ## start the worker thread, hoping to start the progress dialog
    session.delete(order) ##delete order from db
    session.commit()      ##commit to db
    self.change_view("Active", 8) ##func. clean up the table.
    self.worker.finished.emit()   ##emit the finished signal to close the progress dialog

结果是没有显示进度对话框。 gui 只是冻结了一两秒钟,然后条目被删除,没有显示任何进度对话框。

抱歉,我的代码很长,所以我不能把它全部包含在这里,我只是想看看我是否有什么严重的错误。

您的代码存在两个主要问题:

  1. 必须从主 Qt 线程创建和访问 GUI 元素(所有继承或与 QWidget 子类相关的元素)。
  2. 假设需要一些时间的是 delete/commit 操作,那么 那些 操作必须在线程中进行,同时从主线程显示进度对话框,而不是相反。 另外,考虑到 QThread 已经有一个 finished() 信号,你不应该覆盖它。

这是基于您的代码的示例:

class Worker(QThread):
    def __init__(self, session, order):
        super.__init__()
        self.session = session
        self.order = order

    def run(self):
        self.session.delete(self.order)
        self.session.commit()


class Whatever(QMainWindow):
    def __init__(self):
        super().__init__()
        # ...
        self.progressDialog = QProgressDialog("Please wait..", None, 0, 0, self)

    def deleteOrder(self, session, order):
        msg = MsgBox("yn", "Delete Order", 
            "Are you sure you want to delete this order?")
        if msg == MsgBox.Yes: # you should prefer QMessageBox flags
            self.worker = Worker(session, order)
            self.worker.started(self.progressDialog.show())
            self.worker.finished(self.deleteCompleted)
            self.worker.start()

    def deleteCompleted(self):
        self.progressDialog.hide()
        self.change_view("Active", 8)

由于进度对话框在处理过程中应保持打开状态,因此您还应防止用户关闭它。为此,您可以在其上安装事件过滤器并确保接受任何关闭事件;另外,由于QProgressDialog继承自QDialog,Esc键应该被过滤掉,否则它会关闭对话框,而是拒绝并隐藏它.

class Whatever(QMainWindow):
    def __init__(self):
        super().__init__()
        # ...
        self.progressDialog = QProgressDialog("Please wait..", None, 0, 0, self)
        self.progressDialog.installEventFilter(self)

    def eventFilter(self, source, event):
        if source == self.progressDialog:
            # check for both the CloseEvent *and* the escape key press
            if event.type() == QEvent.Close or event == QKeySequence.Cancel:
                event.accept()
                return True
        return super().eventFilter(source, event)