以下是我创建的一个循环:
import mainui
import loginui
from PyQt5 import QtWidgets
import sys
while True:
print('test')
app = QtWidgets.QApplication(sys.argv)
ui = loginui.Ui_MainWindow()
ui.setupUi()
ui.MainWindow.show()
app.exec_()
username=ui.username
app2 = QtWidgets.QApplication(sys.argv)
ui2 = mainui.Ui_MainWindow(username)
ui2.setupUi()
ui2.MainWindow.show()
app2.exec_()
if ui2.exitFlag=='repeat':#Repeat Condition
continue
else: #Exit Condition
sys.exit()
这是一个包含两个PyQt5窗口的循环,这些窗口按顺序显示。当窗口不包含在循环中时,它们可以正常运行,并且在循环的第一次迭代中也可以很好地运行
但是,当满足重复条件时,即使循环确实进行了迭代(再次打印“测试”),ui和ui2窗口也不会再次显示,随后程序点击退出条件并停止
如果您能就为什么不显示窗口以及如何显示窗口提出任何建议,我们将不胜感激
一个重要的前提是:通常您只需要一个QApplication实例
提议的解决办法
在下面的示例中,我使用单个QApplication实例,并使用信号在窗口之间切换
由于您可能需要等待窗口以某种方式关闭,因此您可能更喜欢使用QDialog而不是QMainWindow,但如果出于某种原因您需要QMainWindow提供的功能(菜单、dockbar等),这是一种可能的解决方案:
注意,您也可以通过在QWidget的布局上使用^{} 将菜单栏添加到QWidget中
另一方面,QDialogs更适合于这些情况,因为它们提供了
exec_()
方法,该方法有自己的事件循环,并在对话框关闭之前阻止所有其他内容注意,在本例中,我必须使用QTimer启动第一个对话框。这是因为在正常情况下,信号在将控制权返回到发射器(对话框)之前等待其插槽完成。由于我们不断回忆同一个对话框,这导致了递归:
finished
信号,这导致以下情况:finished
信号尚未返回accepted
信号,导致:exec_()
,但我们正在尝试再次执行它StdErr: QDialog::exec: Recursive call detected
使用QTimer.singleShot可确保信号立即返回,避免
exec_()
的任何递归好吧,但是为什么不起作用呢
如前所述,每个进程通常只应存在一个Q[*]应用程序实例。这实际上并不妨碍随后创建更多的实例:事实上,代码在循环的第一个周期中工作
这个问题与Python垃圾收集有关,以及PyQt和Qt如何处理对C++ QT对象的内存访问,最重要的是应用实例。p>
创建第二个QApplication时,将其分配给一个新变量(
app2
)。在这一点上,第一个仍然存在,并将在进程完成后立即(通过Qt)删除。 相反,当循环重新启动时,您正在覆盖app
,这通常会导致python尽快对上一个对象进行垃圾收集这代表了一个问题,因为Python和Qt需要做“他们的工作”来正确删除现有的QApplication对象和Python引用
如果将以下行放在开头,您将看到第一次正确返回实例,而第二次返回
None
:这里有一个关于StackOverflow的related question以及对其answer的重要评论:
避免垃圾回收的一个解决方法是向应用程序添加持久引用:
但是,正如前面所说的,如果你不真正需要一个新的QApplication实例,那么你应该而不是创建一个新的QApplication实例(这几乎是从未过的情况)
如问题注释中所述,您应该永远不要修改使用
pyuic
生成的文件(也不要尝试模仿它们的行为)。阅读有关using Designer的更多信息。相关问题 更多 >
编程相关推荐