PyQt:设置和清除布局时执行顺序不正确

时间:2017-06-16 02:31:59

标签: python events layout pyqt

self.dialogBox.close() 
self.state = "processing"
self.__clearLayout(self.layout)
print(1)
self.controller.process()

我正在运行以下代码。该对话框是一个PyQt对话框,self.state只是一个当前状态,self.__clearLayout清除PyQt小部件的当前布局,print(1)用于调试目的,self.controller.process()处理事情是什么,需要一段时间。我的目标是清除UI,然后让我的程序进程,但它是乱序。它打印1并开始处理,这告诉我它是有序的,但UI直到完成该过程后才设置。有关如何解决此问题的任何提示?

def processUi(self):
    self.dialogBox.close()
    self.state = "processing"
    self.__clearLayout(self.layout)

    #label
    processingLabel = QtWidgets.QLabel()
    processingLabel.setMaximumSize(500, 500)
    processingLabel.setFont(QtGui.QFont("Mono", 16))
    processingLabel.setText("Processing...may take a few minutes.")

    #set the current layout
    currentLayout = QtWidgets.QVBoxLayout()
    currentLayout.setContentsMargins(0,0,0,0)
    currentLayout.addStretch()
    currentLayout.addWidget(processingLabel)
    currentLayout.addStretch()

    self.layout.addStretch()
    self.layout.addLayout(currentLayout)
    self.layout.addStretch()

    #thread for processing
    processing = multiprocessing.Process(target=self.controller.process, args=())
    processing.start()
    processing.join()
    self.finishedUi()

这是完整的代码。目标是在处理工作时设置您看到的ui代码,并在处理完成后调用finishedUi。

1 个答案:

答案 0 :(得分:0)

我假设您的清晰布局方法与我在this answer中提供的方法相同。

如果是这样,问题出在deleteLater,这会延迟删除,直到控制权返回到事件循环。无法强制处理延迟删除事件(例如QApplication.processEvents()将无效)。相反,有必要使用sip module直接删除小部件:

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())

如果使用多线程,则无需担心sip.delete,因为线程启动后将立即处理任何挂起的删除事件。下面是一个简单的演示,演示了如何使用线程进行非阻塞处理:

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_()