Почему мой экран загрузки не отображается с помощью QThread? - PullRequest
0 голосов
/ 13 апреля 2020

Я делаю настольное приложение, в котором после загрузки баз данных я хочу отобразить экран загрузки. Простой поиск привел меня к использованию gif-файлов в QLabel с объектом QThread. Но в моем случае QThread ничего не покажет. Поток работает нормально, но с моей реализацией что-то не так, и я не могу понять, что именно. Мой пример кода выглядит следующим образом:

from PyQt5.QtWidgets import QWidget, QLabel, QVBoxLayout, QDialog, QApplication, QPushButton
from PyQt5.QtCore import QThread
from PyQt5.QtGui import QMovie
import sys
import time


class myThread(QThread):
    def run(self):

        test = QWidget()   # Only creating this to give parent to QDialog and QLabel objects in upcoming lines
        dialog = QDialog(test)

        vbox = QVBoxLayout()
        lbl = QLabel(test)
        self.moviee = QMovie('Loading.gif')
        lbl.setMovie(self.moviee)
        self.moviee.start()
        vbox.addWidget(lbl)
        dialog.setLayout(vbox)
        dialog.show()

    def stop(self):
        self.moviee.stop()


class Main(QWidget):
    def __init__(self):
        super().__init__()

        print('Thread is to be called here...')
        thread = myThread()
        thread.run()

        print('Thread has been called...')

        btn= QPushButton('Test button')
        vbox = QVBoxLayout()
        vbox.addWidget(btn)
        self.setLayout(vbox)

        time.sleep(5)     # sleep function used to emulate funcitons in actual program

        # thread.stop()
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Main()
    sys.exit(app.exec_())

Блок кода с QMovie объектом отлично работает, когда он находится в Main l oop, поэтому с моей реализацией определенно что-то не так QThread.

1 Ответ

1 голос
/ 13 апреля 2020

Есть несколько проблем с вашим кодом. Как отмечает @musicamante, вы не можете создавать виджеты вне основного потока. Это означает, что вы не можете создать диалог внутри myThread.run. Вместо этого вы можете переместить управление диалоговым окном на Main и использовать слоты и сигналы для открытия и закрытия диалога.

Во-вторых, все трудоемкие задачи, такие как time.sleep(5), следует поместить в myThread.run ,

Имея это в виду, вы могли бы сделать что-то вроде этого

from PyQt5.QtWidgets import QWidget, QLabel, QVBoxLayout, QDialog, QApplication, QPushButton
from PyQt5.QtCore import QThread
from PyQt5.QtGui import QMovie
import sys
import time


class myThread(QThread):
    def run(self):
        # time consuming actions
        time.sleep(5)


class Main(QWidget):

    def __init__(self):
        super().__init__()

        print('Thread is to be called here...')
        self.load()
        print('Thread has been called...')

        btn= QPushButton('Test button')
        vbox = QVBoxLayout()
        vbox.addWidget(btn)
        self.setLayout(vbox)
        self.show()

    def load(self):
        # setup dialog
        dialog = QDialog(self)
        vbox = QVBoxLayout()
        lbl = QLabel(self)
        self.moviee = QMovie('Loading.gif')
        lbl.setMovie(self.moviee)
        self.moviee.start()
        vbox.addWidget(lbl)
        dialog.setLayout(vbox)

        # setup thread
        thread = myThread()
        thread.finished.connect(thread.deleteLater)
        thread.finished.connect(dialog.close)
        thread.finished.connect(dialog.deleteLater)
        thread.start()

        dialog.exec()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Main()
    app.exec()
...