Python 使用QThread在PyQt5中显示QProgressDialog

Python 使用QThread在PyQt5中显示QProgressDialog,python,pyqt5,qthread,pyside2,qprogressdialog,Python,Pyqt5,Qthread,Pyside2,Qprogressdialog,我正在使用PyQt5编写一个管理销售订单的应用程序。创建订单或删除itI时,我希望显示marqee风格的进度对话框,以指示应用程序正在工作。我访问过很多帖子,其中的答案涉及到使用QThread。我尝试过实现它,但似乎遗漏了一些东西。这是我的线程课程 class Worker(QThread): finished = Signal() def run(self): self.x = QProgressDialog("Please wait..",None,0,

我正在使用PyQt5编写一个管理销售订单的应用程序。创建订单或删除itI时,我希望显示marqee风格的进度对话框,以指示应用程序正在工作。我访问过很多帖子,其中的答案涉及到使用QThread。我尝试过实现它,但似乎遗漏了一些东西。这是我的线程课程

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()
在主窗口的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只是冻结一两秒钟,然后条目删除,没有显示任何进度对话框


很抱歉,我的代码太长,所以我无法在这里全部包含,我只是想看看是否有严重错误。

您的代码有两个主要问题:

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)
  • GUI元素(继承的或与QWidget子类相关的所有内容)必须仅从主Qt线程创建和访问
  • 假设删除/提交操作需要一定的时间,那么在显示主线程的进度对话框时,必须在线程中执行这些操作,而不是相反。 此外,请考虑<代码> QTox已经有一个信号,并且不应该覆盖它。
  • 这是一个基于您的代码的示例:

    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)
    

    需要注意的是,与您经历的冻结无关,您永远不会使用类似于
    self.x.setValue(progress)
    的内容更新进度条。这是因为我只希望它在db更新完成之前给出忙碌指示。这是一个选框样式的条,所以最小值和最大值都设置为零。哦,好的。然后我认为解决方案在于两件事中的一件:1-你需要保持对进度对话框的引用“活动”并存储在
    self
    中,我指的是来自你的程序界面的
    self
    ,而不是来自你的类。或2-进度对话框需要有一个父级,它是您的程序界面。在这两种情况下,您都需要找到一种方法将self作为参数传递给QThread(称之为
    zelf
    或其他什么)。请提供一个示例,您应该将删除订单的操作发送给线程,不是QDialog的创建。该对话框应该在主线程上创建,并使用
    QThread.started
    QThread.finished
    信号显示/隐藏。这对理解线程非常有帮助。然而,遵循这一理念意味着我必须为每个处理数据库的函数创建线程。因此,最终主窗口功能将被划分为不同的独立线程。这是一个好的实践吗?任何可能阻塞的操作通常都会移动到单独的线程。请注意,您应该尝试优化它们的使用,避免不必要的创建(您可以重用线程,每次只需正确设置它)。另外,请查看QRunnable和QThreadPool。