问题描述
我正在使用PyQt5编写一个管理销售订单的应用程序。创建或删除订单时,我想显示一个marqee样式进度对话框以指示该应用程序正在运行。我访问过很多帖子,其中涉及使用QThread的答案。我试图实现它,但似乎我缺少了一些东西。这是我的线程课程。
class Worker(QThread):
finished = Signal()
def run(self):
self.x = QProgressDialog("Please wait..",None,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只冻结一两秒钟,然后删除该条目,而不会显示任何进度对话框。
对不起,我的代码很长,因此我无法在此处包括所有内容,我只是想看看我是否遇到了严重错误。
解决方法
您的代码有两个主要问题:
-
必须创建
- GUI元素(所有与QWidget子类继承或相关的元素),并只能从Qt主线程中仅访问。
- 假设删除/提交操作需要花费一些时间,那么这些 操作必须在线程中执行,同时显示来自主线程的进度对话框,而不是相反。
另外,请考虑
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,self)
def deleteOrder(self,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..",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)