Search code examples
pythonmultithreadingpython-3.xpyqt5signals-slots

How can I send a Label to gui from another thread - PyQt


This is a simple manga reader, I am trying to load images without freezing the main window, I have tried to do this with threads but couldn't send images to main window, what am i doing wrong? Also I am new to python if there is another way i would like to know thanks.

from PyQt5 import QtCore, QtGui, QtWidgets
import os

class MainWin(QtWidgets.QMainWindow):

    ...

    def add_widget(self, data):
        self.verticalLayout.addWidget(data)

    def file_open(self):
        adres = QtWidgets.QFileDialog.getExistingDirectory()
        self.loader = LoaderThread(adres)
        self.loader.start()
        self.loader.pics.connect(self.add_widget)


class LoaderThread(QtCore.QThread):

    pics = QtCore.pyqtSignal(object)

    def __init__(self, nAdres):
        QtCore.QThread.__init__(self)
        self.adres = nAdres

    def run(self):
        liste = os.listdir(self.adres)
        order = 0
        for i in liste:
            label = QtWidgets.QLabel()
            pixmap = QtGui.QPixmap(self.adres + '/' + liste[order])
            label.setPixmap(pixmap)
            self.pics.emit(label)
            order += 1

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    win = MainWin()
    win.show()
    sys.exit(app.exec_())

Solution

  • You can't create widgets or pixmaps outside of the GUI thread. So just create a QImage in the worker thread and then create the label and pixmap in the slot:

    class LoaderThread(QtCore.QThread):
        ...
        def run(self):
            liste = os.listdir(self.adres)
            order = 0
            for i in liste:
                image = QtGui.QImage(self.adres + '/' + liste[order])
                self.pics.emit(image)
                order += 1
    
    
    class MainWin(QtWidgets.QMainWindow):
        ...
        def add_widget(self, image):
            label = QtWidgets.QLabel()
            label.setPixmap(QtGui.QPixmap.fromImage(image))
            self.verticalLayout.addWidget(label)