以下是我的代码,用于列出目录的所有子目录。我用它来了解QThread以及PySide中的信号和插槽。问题是,当我不在Qtcore.QApplication.processEvents()类的scan()方法中使用Main时,该代码不起作用。事件循环是否尚未运行?

import sys
import os
import time
from PySide import QtGui, QtCore

class Scanner(QtCore.QObject):
    folderFound = QtCore.Signal(str)
    done = QtCore.Signal()
    def __init__(self, path):
        super(Scanner, self).__init__()
        self.path = path

    @QtCore.Slot()
    def scan(self):
        for folder in os.listdir(self.path):
            time.sleep(1)
            self.folderFound.emit(folder)

class Main(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.resize(420,130)
        self.setWindowTitle('Threads')
        self.lyt = QtGui.QVBoxLayout()
        self.setLayout(self.lyt)

        self.topLyt = QtGui.QHBoxLayout()
        self.lyt.addLayout(self.topLyt)
        self.scanBtn = QtGui.QPushButton('Scan')
        self.scanBtn.clicked.connect(self.scan)
        self.clearBtn = QtGui.QPushButton('Clear')
        self.topLyt.addWidget(self.scanBtn)
        self.topLyt.addWidget(self.clearBtn)

        self.folders = list()

        self.show()

    def scan(self):
        self.th = QtCore.QThread()
        scanner = Scanner(r"D:\\")
        scanner.moveToThread(self.th)

        scanner.folderFound.connect(self.addFolder)
        scanner.done.connect(scanner.deleteLater)
        scanner.done.connect(self.quit)

        self.th.started.connect(scanner.scan)
        self.th.start()

        QtCore.QApplication.processEvents()

    @QtCore.Slot()
    def addFolder(self, folder):
        lbl = QtGui.QLabel(folder)
        self.folders.append(lbl)

        self.lyt.addWidget(lbl)

    @QtCore.Slot()
    def quit(self):
        self.th.quit()
        self.th.wait()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main = Main()
    app.exec_()

最佳答案

您的示例完全可行,这是纯属偶然。

当您尝试调用QtCore.QApplication.processEvents()时,将引发NameError,因为QApplication类实际上位于QtGui模块中,而不是在QtCore模块中。但是,引发异常具有防止scanner对象被垃圾回收的副作用,因此线程似乎可以正常运行。

修复代码的正确方法是保留对scanner对象的引用,并摆脱processEvents行,这是不需要的:

def scan(self):
    self.th = QtCore.QThread()
    # keep a reference to the scanner
    self.scanner = Scanner(r"D:\\")
    self.scanner.moveToThread(self.th)

    self.scanner.folderFound.connect(self.addFolder)
    self.scanner.done.connect(self.scanner.deleteLater)
    self.scanner.done.connect(self.quit)

    self.th.started.connect(self.scanner.scan)
    self.th.start()

其余代码都可以,并且该示例现在可以按预期工作。

关于python - 为什么需要processEvents()才能使QThread工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48801992/

10-09 09:02