完成GUI呈现后,在程序启动时执行长时间运行的代码
我有一个应用程序可以从命令行启动,使用可选的文件名作为参数。如果存在这个文件应该在启动时加载。由于文件的处理需要一些时间,因此fileOpen()
会阻止程序并显示加载指示符。完成GUI呈现后,在程序启动时执行长时间运行的代码
在正常操作期间,这没关系。但是,当我尝试在启动时执行相同操作(如下所示)时,窗口的轮廓出现在show()
之后,但其内容直到app.exec_()
才呈现。
我的问题:我该如何处理这种情况?
-
app.exec_()
之前,我不能把fileOpen()
因为那时GUI尚未完全呈现。而且我不能通知用户加载仍在处理中。 - 我不能放?之后
app.exec_()
因为它不会被执行直到程序结束。
示例代码:
def main(args):
app = QtGui.QApplication()
mainwindow = MainWindow()
mainwindow.show()
if args.filename:
mainwindow.fileOpen(args.filename)
ret_val = app.exec_()
sys.exit(ret_val)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('filename', help='(optional) file to load at startup')
args = parser.parse_args()
main(args)
我发现,单次定时器可以解决这个问题,但我只用Openbox的窗口管理器测试它在Linux上,所以我不能保证它可以在所有平台上运行。您可能需要调整超时的持续时间以使其在您的系统上正常工作。
下面是一个简单的演示,对我的作品:
import sys
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.edit = QtWidgets.QTextEdit(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.edit)
def fileOpen(self, path):
QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor)
QtCore.QThread.sleep(3)
self.edit.setText(open(path).read())
QtWidgets.qApp.restoreOverrideCursor()
def main():
app = QtWidgets.QApplication(sys.argv)
mainwindow = MainWindow()
mainwindow.setGeometry(600, 100, 300, 200)
mainwindow.show()
QtCore.QTimer.singleShot(50, lambda: mainwindow.fileOpen(__file__))
sys.exit(app.exec_())
if __name__ == '__main__':
main()
注意:此方法不适用于Linux操作系统(X11)工作(见注释并ekhumoro答案)
感谢所有答案。虽然他们每个人都有一些缺点(将在下面讨论),他们把我带到了正确的解决方案:
呼叫qApp.processEvents()
后mainwindow.show()
:这正是我们想要做的:
def main(args):
app = QtGui.QApplication()
mainwindow = MainWindow()
mainwindow.show()
qApp.processEvents()
if args.filename:
mainwindow.fileOpen(args.filename)
ret_val = app.exec_()
sys.exit(ret_val)
原因:
- 我们想要处理与主窗口绘图相关的事件。
- 然后执行我们的自定义代码。
- 然后继续正常的事件循环。
的其他建议讨论:
为什么我不叫qApp.processEvents()
在fileOpen()
:这将是积极的所有fileOpen()
电话。在长时间运行的文件公开呼叫期间处理其他事件可能会导致意外的行为,如果应用程序没有按照这个设计,例如,您可以在第一次运行时发出第二个fileOpen()
。
为什么我不使用定时器来执行fileOpen()
:我想在GUI完全加载之后但在任何用户输入之前执行代码。计时器只是正确执行正确的执行顺序。此外,根据CPU,系统使用情况和其他因素,正确的延迟可能会有所不同,从而使该解决方案不够稳固。
此解决方案在X11(Linux)上不起作用。调用'qApp.processEvents()'在那里没有任何效果,因为窗口管理器异步创建窗口框架(所以您正在等待* system * -level事件,而不是* application * -level事件)。某种完全跨平台的解决方案需要基于定时器的解决方案。当然,您可以检测平台并相应地应用不同的方法。 (有关更多详细信息,请参见[X11特性](https://doc.qt.io/qt-5/application-windows.html#x11-peculiarities))。 – ekhumoro
你是什么意思,当你说:**图形用户界面还没有完全呈现**? – eyllanesc
尝试在fileOpen()内调用qApp.processEvents() – eyllanesc