今天我遇到了一个有趣的情况,当下面的一行在执行它之前被执行(上面的一行)。下面是这种情况的简单版本。简要说明:有三个QGroupBox()
连接到同一个窗口:groupboxA
、groupboxB
和groupboxC
。
Groupbox B已隐藏。单击“确定”按钮可取消隐藏第二个groupBox B并隐藏第一个groupBox a。重复单击可继续此隐藏/取消隐藏事件序列。你知道吗
最后一行是调用calcA()
方法,它的处理大约需要2-3秒才能完成。
一个问题是:即使对calcA()
的调用在最后一行,它也是在QGroupBoxes可见性发生变化之前执行的,而上面编写的代码负责这些变化。我想知道为什么会发生这种情况,以及如何避免这种情况。你知道吗
from PyQt4 import QtGui, QtCore
class MyApp(object):
def __init__(self):
super(MyApp, self).__init__()
app = QtGui.QApplication(sys.argv)
self.mainWidget = QtGui.QWidget()
self.mainLayout = QtGui.QVBoxLayout()
self.mainWidget.setLayout(self.mainLayout)
# A
self.groupboxA = QtGui.QGroupBox()
self.layoutA = QtGui.QVBoxLayout()
self.groupboxA.setLayout(self.layoutA)
lineA = QtGui.QTextEdit('This is QGroupBox A')
self.layoutA.addWidget(lineA)
# B
self.groupboxB = QtGui.QGroupBox()
self.layoutB = QtGui.QVBoxLayout()
self.groupboxB.setLayout(self.layoutB)
self.groupboxB.setHidden(True)
labelB = QtGui.QLabel('This is QGroupBox B')
self.layoutB.addWidget(labelB)
# C
self.groupboxC = QtGui.QGroupBox()
self.layoutC = QtGui.QVBoxLayout()
self.groupboxC.setLayout(self.layoutC)
okButton = QtGui.QPushButton('OK')
okButton.clicked.connect(self.OK)
self.layoutC.addWidget(okButton)
self.mainLayout.addWidget(self.groupboxA)
self.mainLayout.addWidget(self.groupboxB)
self.mainLayout.addWidget(self.groupboxC)
self.mainWidget.show()
sys.exit(app.exec_())
def calcA(arg=None):
print "Task started..."
for i in range(5000000):
pass
print '...task completed.'
def OK(self):
if self.groupboxA.isHidden(): self.groupboxA.setHidden(False)
else: self.groupboxA.setHidden(True)
if self.groupboxB.isHidden(): self.groupboxB.setHidden(False)
else: self.groupboxB.setHidden(True)
self.calcA()
if __name__ == '__main__':
MyApp()
直到控件返回到Qt事件循环(一旦slot
OK
完成),GUI的更新才会发生。你知道吗这是一个常见的问题,当您有一个长期运行的插槽,并希望图形用户界面的变化是可见的插槽结束之前。这个问题有一些答案,其中详细说明了一些解决方法: Label in PyQt4 GUI not updating with every loop of FOR loop
基本上,将长时间运行的工作卸载到QThread通常是最好的主意,但是只有在长时间运行的代码不直接与GUI交互的情况下,您才能轻松地做到这一点(您无法从线程与GUI交互,因此这会变得很棘手)。线程很容易出错,并且会严重破坏程序的稳定性,因此您可能不想走这条路。你知道吗
另一个选项是在
__init__
方法中调用QApplication.instance().processEvents()
(或将app
分配给self.app
),然后在更新GUI的调用之后立即调用self.app.processEvents()
(如setHidden()
),但我通常会尽量避免这种情况,因为我认为这是一种不好的做法。你知道吗最后的解决方案,也是在您的情况下最有效的解决方案,是调用
QTimer.singleShot(1,self.calcA)
,而不是self.calcA
。这将把控制权返回到事件循环,事件循环将更新GUI,然后调用self.calcA
。你知道吗问题是你有这样的伪代码:
微妙的是,对GUI所做的修改只有在Qt事件循环恢复之后,即在OK()返回之后才会得到“处理”。这就是为什么看起来好像长时间运行的函数是在上面的行之前执行的。不是这样,但是上面的行只有在OK()返回时才得到“activate”,这是在长时间运行的函数完成之后。你知道吗
因此,如果您想让GUI更新在可见之前完成,就不能在OK中长时间运行函数。解决方案取决于长时间运行的函数:如果它是一个循环,您可以这样编写:
然后可以替换为:
否则,只需将长时间运行的函数移到QThread。您必须考虑以下问题:
相关问题 更多 >
编程相关推荐