首页 > 解决方案 > PyQt5;使用 QRunnable 和 QThreadPool 的线程问题

问题描述

似乎我在我的应用程序中运行线程时遇到如下问题:在我的 MainForm 类中,我有:

.
.
self.threadPool = QtCore.QThreadPool()
self.threadPool.setMaxThreadCount(4)
.
.
def openFileFcn(self):
worker = **Worker**(self, **self.ImageViewer.showImages**, self.files)
self.threadPool.start(worker)

其中Worker是一个包装器 QRunnable,定义为:

class Worker(QtCore.QRunnable):
    def __init__(self, fn, *args, **kwargs):
        QtCore.QRunnable.__init__(self)
        self.fn = fn
        self.args = args
        self.kwargs = kwargs

    def run(self) -> None:
        self.fn(*self.args, **self.kwargs)

self.ImageViewer.showImages指的是 ImageViewer 类的以下部分:

    def loadImg(self, file):
        tabName = str()
        if len(file) > 15: tabName = file[0:13] + "..."

        widget = ImageViewer()
        localPath = os.path.abspath(file)
        localPath = QtCore.QDir().filePath(localPath)
        pixmap = QtGui.QPixmap(localPath)
        widget.setImage(pixmap)
        self.tabwidget.addTab(widget, self.mainFormHandle.sharedData.imgIcon, tabName)
        self.tabwidget.setCurrentIndex(self.tabwidget.currentIndex() + 1)

    def **showImages**(self, files):
        files = [file.lower() for file in files]
        for file in files:
            self.loadImg(file)

当我运行这段代码时,什么都没有发生。它只是冻结,一段时间后应用程序以退出代码 -1073740791 (0xC0000409) 关闭。你认为是什么原因?

标签: pythonpyqtpyqt5qthreadqrunnable

解决方案


问题似乎是您试图从主线程之外的另一个线程创建小部件。您只能从主线程创建小部件,但由于loadImg()创建了多个小部件,因此从线程池调用它会使您的应用程序崩溃。解决这个问题的一种方法是loadImg()分成两种方法,一种方法是加载像素图,另一种方法是创建ImageViewers 并添加选项卡。然后可以将第一个移到线程池中,并且您可以使用信号在每次加载像素图时自动调用第二个。例如:

class TabArea(QtWidgets.QWidget):
    pixmap_loaded = QtCore.pyqtSignal(str, QtGui.QPixmap)

    def __init__(self, parent=None):
        ...
        self.pixmap_loaded.connect(self.addTab)

    def loadImg(self, file):
        localPath = os.path.abspath(file)
        localPath = QtCore.QDir().filePath(localPath)
        pixmap = QtGui.QPixmap(localPath)
        # emit pixmap and file name
        self.pixmap_loaded.emit(file, pixmap)

    def addTab(self, file, pixmap):
        tabName = str()
        if len(file) > 15: tabName = file[0:13] + "..."
        widget = ImageViewer()
        widget.setImage(pixmap)
        self.tabwidget.addTab(widget, self.mainFormHandle.sharedData.imgIcon, tabName)
        self.tabwidget.setCurrentIndex(self.tabwidget.currentIndex() + 1)

    def showImages(self, files):
        files = [file.lower() for file in files]
        for file in files:
            self.loadImg(file)

推荐阅读