getOpenFileName 上的进度条
Posted
技术标签:
【中文标题】getOpenFileName 上的进度条【英文标题】:Progress Bar over getOpenFileName 【发布时间】:2014-01-27 09:54:33 【问题描述】:在我的应用程序中,我有以下行打开一个文件对话框窗口。获得文件名后,我会进行一系列处理,这需要相当长的时间,一旦完成,工作区就可以供用户使用了。
filename, _ = QtGui.QFileDialog.getOpenFileName(self, 'Open file', os.curdir, "*.cws")
文件对话框是一个模态窗口(默认情况下),这很棒,因为它可以防止用户在工作区尚未准备好使用时做愚蠢的事情。我想在某处放置一个进度条,以了解已处理了多少。我制作了另一个对话框窗口,其中显示了一个进度条和一些其他信息。
现在,由于文件对话框窗口是模态的,它只是在我的工作区正在处理时冻结在那里,并且只有在一切完成后才会弹出进度对话框。
我已经研究过将文件对话框窗口设置为非模式,但我认为这是不可能的。我在想也许强迫它关闭,然后立即弹出我的进度对话框窗口并接管该模式。如何以编程方式关闭文件对话框窗口?我不知道如何获取表单的参考。
或者您对如何解决这个问题有更好的建议?
【问题讨论】:
问题是你在关闭文件对话框后做了一些繁重的处理,这会阻止事件被处理。您应该考虑在另一个线程中进行这种繁重的处理。文件对话框的模式不会导致问题。 从文件对话窗口收到文件名后,处理就开始了。窗户本身仍然开着。那么你的意思是说close事件是因为我自己的繁重处理而无法执行吗?按照您的建议,我将在另一个线程中尝试一下。那么我应该让这个其他线程弹出模态进度窗口,以防止用户做其他事情吗?谢谢! 是的,在您完成繁重的处理之前,不会处理关闭事件。这个other thread
应该做繁重的处理,它不应该做任何GUI 工作。将与 GUI 相关的内容保留在主线程中,并将繁重的工作移至新的工作线程。应该在主线程中创建并显示模态进度窗口。
我刚做了这个,是的,效果很好!我实际上想知道是什么导致文件对话框关闭,因为它没有在返回文件名后立即关闭。凉爽的。现在,如果我的进度条在主线程中,我将如何从新线程向它传递有关进度状态的信息?让新线程显示进度条是不是很糟糕?
是的,你真的应该把你的 GUI 东西放在主线程中。要将有关进度状态的信息从工作线程传递到主线程,您可以使用信号和插槽。
【参考方案1】:
正如 thuga 所说,您的应用程序事件循环因繁重的处理而陷入困境。 因此,在处理运行时不会处理事件(尤其是绘制事件),从而导致 GUI 冻结。
在我看来,你有两个选择:
强制处理事件(不是很经典但可能有效):
这取决于您的“繁重处理”是如何完成的。 假设挂起循环的代码“在你的手中”(不在第三方库中)。 您可以在其中添加尽可能多的电话到QApplication.processEvents。
如果处理是基于循环的,它可能看起来像:
for item in itemList:
...processitem...
QtGui.QApplication.processEvents()
这是在不应注意的部分代码中向 GUI 添加依赖项的主要缺点。 如果您的代码不是基于循环的,那么您将不得不添加几个对 processEvents 的调用,这会污染处理代码。
停止挂起事件循环(更复杂但更易于维护)
这意味着您将不得不按照 thuga 的建议处理线程和/或子进程。 此解决方案假设 GUI 代码和业务代码分离得足够好。
您可以查看this article from Qt Quarterly,它提供了有关此问题的一些亮点。 由于 python 全局解释器锁 (GIL),您可能看不到线程更好的结果。 考虑使用multiprocessing 库。
【讨论】:
第一个选项:可以使用回调机制将 GUI 与后端分开。后端只注册一个处理程序,它以调用者可以设置的频率调用该处理程序。这种技术的一个例子是sqlite3.set_progress_handler。以上是关于getOpenFileName 上的进度条的主要内容,如果未能解决你的问题,请参考以下文章