PyQt5; проблема с многопоточностью с использованием QRunnable и QThreadPool - PullRequest
0 голосов
/ 04 мая 2020

Кажется, что у меня проблема с запуском потоков в моем приложении следующим образом: в моем классе 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). Что вы предлагаете быть причиной?

1 Ответ

0 голосов
/ 04 мая 2020

Кажется, проблема в том, что вы пытаетесь создать виджеты из другого потока, а не из основного потока. Вы можете создавать виджеты только из основного потока, но поскольку loadImg() создает несколько виджетов, вызов его из пула потоков приводит к сбою приложения. Один из способов обойти это - разделить loadImg() на два метода: один метод, который загружает растровые изображения, и другой, который создает ImageViewer с и добавляет вкладки. Первый можно затем переместить в пул потоков, и вы можете использовать сигнал для автоматического вызова второго при каждой загрузке растрового изображения. Например:

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