0

What I'm trying to accomplish is fetching results from an API and the results are a bunch of classes that take a bit of time to fetch.

Note that each of the results contains a link to a picture that will take time to load on the PyQt5 application.

I need to make the whole process listed above happens in another thread.

What I tried is using QThread and signals which I do not think that Im doing correctly so here is a minimal reproducable example.

| - [Main.py]

class Main(object):
    def __init__(self):
        self.results = MyAPISearchEngine("SearchQuery") # I can switch from normal list to a generator

    def setup_ui(self):
        self.vLayout = QVBoxLayout(self.scrollAreaW)

        for r in self.results:
            def loadData(data):
                result, img = data

                wrapperW = QWidget()
                title = QLabel(wrapperW)
                title.setText(str(result))

                imgLabel = QLabel(wrapperW)
                imgLabel.setPixmap(img)

                    self.vLayout.addWidget(wrapperW)
            self.thread = Threads.MyThread(r)
            self.thread.dataLoaded.connect(loadData)
            self.thread.start()

| - [Threads.py]

Assuming that the picture url is inside my class's Object.url and the string representation of Object is its title.

class MyThread(QThread):
    dataLoaded = pyqtSignal(object)
    def __init__(self, result, *args, **kwargs):
        super(MyThread, self).__init__(*args, **kwargs)
        self.result = result
        print("Thread is started!")

    def start(self):
        print("Thread is started!!")
        data = urlopen(self.result.url).read()
        image = QtGui.QPixmap()
        image.loadFromData(data)
        x = (self.result, image)
        self.dataLoaded.emit(x)

atm the thread is not working it just prints out this

Thread is started!
Thread is started!
QThread: Destroyed while thread is still running

if you are wondering what is attribute project in setup_ui all about

if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    Project = QtWidgets.QTabWidget()
    ui = Main()
    ui.setup_ui(Project)
    Project.show()
    sys.exit(app.exec_())
Aoof
  • 322
  • 2
  • 10
  • change `thread` to `self.thread` – eyllanesc Nov 27 '19 at 03:22
  • the application still not respond once the action loop starts – Aoof Nov 27 '19 at 03:32
  • provide a [mre] – eyllanesc Nov 27 '19 at 03:33
  • On the other hand, do not use QPixmap in another thread, use QImage, send it to the main thread and just convert it to QPixmap if necessary with `qpixmap = QPixmap.fromQImage(qimage)` – eyllanesc Nov 27 '19 at 03:34
  • upps, don't change `thread` with `self.thread`, instead just change `thread = Threads.MyThread(r)` with `thread = Threads.MyThread(r, parent=self)` – eyllanesc Nov 27 '19 at 03:37
  • ok that makes sense. but it still not responding till the loop finishes and sometimes crashes with `TypeError: MyThread.dataLoaded[] signal has 0 argument(s) but 1 provided` – Aoof Nov 27 '19 at 03:39
  • 1
    1) change `dataLoaded = pyqtSignal(object)` to `dataLoaded = pyqtSignal(QImage, object)`, 2) change `image = QtGui.QPixmap()` to `image = QtGui.QImage()` 3) change `self.dataLoaded.emit(x)` to `self.dataLoaded.emit(image, self.result)`, 4) change `imgLabel.setPixmap(img)` to `imgLabel.setPixmap(QPixmap.fromImage(img))`, 5) change `def loadData(data):` to `def loadData(img, result):`, 6) remove `result, img = data` – eyllanesc Nov 27 '19 at 03:47
  • since the application freezes on loops should I create the loop inside the Thread and the results from the APISearchEngine and make the loop as the loadData function? – Aoof Nov 27 '19 at 03:52
  • 1
    How many urls do you have? if there are less than 10 there should be no problems, but if you want a response with great certainty you must provide a [mre], otherwise you ask me to speculate which is not part of my style. – eyllanesc Nov 27 '19 at 03:53
  • Oh my god the results are unreal, Im so thankful but it does not freeze on loops anymore, I think the problem was errors that made it freeze – Aoof Nov 27 '19 at 03:53
  • Why do you use urlopen? urlopen is blocking and in Qt there is a better option: Qt Network – eyllanesc Nov 27 '19 at 03:54
  • how does that work, recommend a discussion about it? – Aoof Nov 27 '19 at 03:55
  • If you have many urls it is better to use an iterator and a QTimer that launches the tasks. – eyllanesc Nov 27 '19 at 03:55
  • see https://stackoverflow.com/questions/41665954/using-pyqt4-to-download-thousands-of-pdfs-from-url – eyllanesc Nov 27 '19 at 03:56
  • ironically I used the QTimer in the same ScrollArea that the function above lists images into to create an auto scroller, can I use it also to replace urlopen? – Aoof Nov 27 '19 at 03:57
  • Check the example of the link where they download files using Qt Network with PyQt4 (translating it to PyQt5 is almost a copy-paste) which is the same as you do. – eyllanesc Nov 27 '19 at 03:59

0 Answers0