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

2024-04-26 18:47:07 发布

您现在位置:Python中文网/ 问答频道 /正文

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。你知道吗


Tags: 代码selfcloseprocess对话框stateprintlayout
1条回答
网友
1楼 · 发布于 2024-04-26 18:47:07

我假设您的clear布局方法与我在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_()

相关问题 更多 >