簡體   English   中英

為什么processEvents()需要讓QThread工作?

[英]Why is processEvents() needed to get QThread to work?

下面是我列出目錄的所有子目錄的代碼。 我用它來理解PySide中的QThread和信號以及插槽。 問題是,當我沒有在Main類的scan()方法中使用Qtcore.QApplication.processEvents()時,代碼不起作用。 事件循環是否尚未運行?

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

其余的代碼都沒問題,現在示例將按預期工作。

事件循環不是背后運行的東西。 總是那個必須經營它的人。 一個線程不能同時做兩件事:如果你的代碼是控制的位置,那么顯然事件循環不是! 您需要從代碼返回到事件循環,並確保從事件循環中調用代碼。 從事件循環中調用任何類型的UI信號,網絡事件或超時,因此很可能您的代碼已經在調用堆棧上具有事件循環。 為了保持循環旋轉,你必須返回它。

永遠不要使用processEvents - 而是反轉控件,以便事件循環調用代碼,然后執行一大堆工作,最后返回到事件循環。

“保持我的代碼在事件循環中工作”的習語是一個零持續時間計時器。 執行工作的可調用程序附加到超時信號。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM