Python 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 =

我正在运行以下代码。该对话框是一个PyQt对话框,
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_()