Python PyQt:设置和清除布局时执行顺序不正确
我正在运行以下代码。该对话框是一个PyQt对话框,Python PyQt:设置和清除布局时执行顺序不正确,python,events,layout,pyqt,Python,Events,Layout,Pyqt,我正在运行以下代码。该对话框是一个PyQt对话框,self.state只是一个当前状态,self.\uu clearLayout清除PyQt小部件的当前布局,print(1)用于调试,而self.controller.process()是处理事情的工具,需要一段时间。我的目标是清除UI,然后让我的程序处理,但它是无序的。它打印1并开始处理,这告诉我它是有序的,但UI直到处理完成后才进行设置。关于如何解决这个问题有什么建议吗 self.dialogBox.close() self.state =
self.state
只是一个当前状态,self.\uu clearLayout
清除PyQt小部件的当前布局,print(1)
用于调试,而self.controller.process()
是处理事情的工具,需要一段时间。我的目标是清除UI,然后让我的程序处理,但它是无序的。它打印1
并开始处理,这告诉我它是有序的,但UI直到处理完成后才进行设置。关于如何解决这个问题有什么建议吗
self.dialogBox.close()
self.state = "processing"
self.__clearLayout(self.layout)
print(1)
self.controller.process()
这是完整的代码。我们的目标是设置处理工作时看到的ui代码,一旦处理完成,调用finishedUi。我假设您的clear layout方法与我给出的方法相同 如果是这样,问题在于
deleteLater
,它会延迟删除,直到控件返回到事件循环。无法强制处理延迟删除事件(例如,QApplication.processEvents()
将不起作用)。相反,有必要使用以下命令直接删除小部件:
如果使用多线程,则无需使用sip.delete
,因为任何挂起的删除事件都将在线程启动后立即处理。下面是一个简单的演示,演示如何使用线程进行非阻塞处理:
import sip
def clearLayout(self, layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
sip.delete(widget)
else:
self.clearLayout(item.layout())
我假设你的清晰布局方法与我给出的相同 如果是这样,问题在于
deleteLater
,它会延迟删除,直到控件返回到事件循环。无法强制处理延迟删除事件(例如,QApplication.processEvents()
将不起作用)。相反,有必要使用以下命令直接删除小部件:
如果使用多线程,则无需使用sip.delete
,因为任何挂起的删除事件都将在线程启动后立即处理。下面是一个简单的演示,演示如何使用线程进行非阻塞处理:
import sip
def clearLayout(self, layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
sip.delete(widget)
else:
self.clearLayout(item.layout())
你是对的,我使用的是你之前发布的版本,我把它改成了这个版本,但是行为没有改变。用户界面仍然冻结。@Aleks。行为确实发生了变化。如果清除布局后放置
QApplication.processEvents()
,ui将立即更新。但是,您的处理功能会被阻塞,因此以后仍然无法与ui交互。要实现这一点,您需要在单独的线程中进行处理。但是,这是一个完全不同的问题-您当前的问题只询问如何在清除布局时修复执行顺序。谢谢,我知道使用不同的进程,我正在使用它们,我只是简化了此问题的代码。在添加了我不知道的QApplication.processEvents()之后,行为发生了变化。但是,现在它会在流程完成期间和之后阻止我的整个ui。当我点击ui上的任何地方时,计算机只会发出阻塞噪音。@Aleks。我已经解决了你原来问题中提到的具体问题。当然,你的ui会阻塞:正如我所说的,如果你想避免这种情况,你需要在一个单独的线程中进行处理。正如我前面所说的,我的代码只是我正在做的一个简化版本。self.controller.process()实际上是作为单独的进程调用的。在添加QApplication.processEvents()行后,进程完成后的UI保持阻塞状态。如果没有这一行,我的ui将至少在流程完成后解锁。再次感谢所有的帮助。你是正确的,我使用了你发布的上一个版本,并将其更改为此版本,但是行为没有改变。用户界面仍然冻结。@Aleks。行为确实发生了变化。如果清除布局后放置QApplication.processEvents()
,ui将立即更新。但是,您的处理功能会被阻塞,因此以后仍然无法与ui交互。要实现这一点,您需要在单独的线程中进行处理。但是,这是一个完全不同的问题-您当前的问题只询问如何在清除布局时修复执行顺序。谢谢,我知道使用不同的进程,我正在使用它们,我只是简化了此问题的代码。在添加了我不知道的QApplication.processEvents()之后,行为发生了变化。但是,现在它会在流程完成期间和之后阻止我的整个ui。当我点击ui上的任何地方时,计算机只会发出阻塞噪音。@Aleks。我已经解决了你原来问题中提到的具体问题。当然,你的ui会阻塞:正如我所说的,如果你想避免这种情况,你需要在一个单独的线程中进行处理。正如我前面所说的,我的代码只是我正在做的一个简化版本。self.controller.process()实际上是作为单独的进程调用的。在添加QApplication.processEvents()行后,进程完成后的UI保持阻塞状态。如果没有这一行,我的ui将至少在流程完成后解锁。再次感谢所有的帮助。
from PyQt5 import QtCore, QtWidgets
class Worker(QtCore.QThread):
progressChanged = QtCore.pyqtSignal(int)
def run(self):
for tick in range(10):
self.msleep(500)
self.progressChanged.emit(tick + 1)
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.button = QtWidgets.QPushButton('Start', self)
self.button.clicked.connect(self.handleButton)
self.frame = QtWidgets.QFrame(self)
self.frame.setMinimumHeight(100)
self.frame.setLayout(QtWidgets.QVBoxLayout())
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.frame)
layout.addWidget(self.button)
def handleButton(self):
self.button.setEnabled(False)
self.clearLayout(self.frame.layout())
label = QtWidgets.QLabel('Starting')
self.frame.layout().addWidget(label)
def progress(tick):
label.setText('Processing... Count = %d' % tick)
def finish():
label.setText('Finished')
self.button.setEnabled(True)
thread.deleteLater()
thread = Worker(self)
thread.finished.connect(finish)
thread.progressChanged.connect(progress)
thread.start()
def clearLayout(self, layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
else:
self.clearLayout(item.layout())
if __name__ == '__main__':
app = QtWidgets.QApplication(['test'])
window = Window()
window.setGeometry(600, 100, 300, 200)
window.show()
app.exec_()