Анимация загрузки PyQt5

Существует некоторое Python-приложение, использующее PyQt5. В процессе его работы иногда происходят события, которые длятся длительное время, например - проверка введённого пароля.

Как реализовать проигрывание, например, .gif - анимации или чего-то подобного во время такого события?

МВП длительного события:


someList = [AbstractUser for AbstractUser in someUserList if (AbstractUser.login == enteredLogin)]

someMatchesList = []

for i in someOtherList:
    try:
        if someList[0].password == (hashlib.pbkdf2_hmac('sha256', enteredPassword.encode('utf-8'), bytes.fromhex(i), 256256).hex()):
           #Успешный вход
           break
        else:
           someMatchesList.append(False)
           continue

    except IndexError:
        #Неверный логин

if [bool for bool in someMatchesList if (bool == True)] == []:
    #Неверный пароль

Ответы (1 шт):

Автор решения: S. Nick

События, которые длятся длительное время, необходимо выполнять в дополнительном потоке, чтобы не блокировать интерфейс.

А проигрывание, например, .gif-анимации или чего-то подобного, это уже зависит от вашего вкуса.

Вот вам простенький вариант, попробуйте.

import sys
from random import randint
from PyQt5.QtCore import QThread, pyqtSignal, Qt, QSize, QFile
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QLabel, 
    QMessageBox, QSizePolicy, QLineEdit, QVBoxLayout)
from PyQt5.QtGui import QMovie, QPixmap


class Thread(QThread):
    dataThread = pyqtSignal(str)
    
    def __init__(self, username, password, someUserList, someOtherList):
        QThread.__init__(self)
        self.username = username
        self.password = password
        self.someUserList = someUserList
        self.someOtherList = someOtherList
        self.someMatchesList = []
        print(username, password, someUserList, someOtherList)

    def run(self):
# !!! vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
#       попробуйте заменить то что ниже своим кодом,
#       события, которого длятся длительное время.
        for i in range(randint(1_000_000, 100_000_000)):
            pass
        if i > 50_000_000:
            self.dataThread.emit(f"successfully")
        else:
            self.dataThread.emit(f"error")
# !!! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


class LoginPage(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.image_label = QLabel(alignment=Qt.AlignCenter)
        self.image_label.setPixmap(QPixmap("head3.png"))
        self.login_label = QLabel(text=self.tr("LOG IN"), alignment=Qt.AlignCenter)
        font = self.login_label.font()
        font.setPointSize(30)
        self.login_label.setFont(font)
        self.login_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        
        self.email_username_lineedit = QLineEdit(placeholderText=self.tr("Email or username"))
        self.password_lineedit = QLineEdit(placeholderText=self.tr("Password"), 
                                           echoMode=QLineEdit.Password)
            
        self.enter_button = QPushButton(self.tr("Enter"))
        self.enter_button.clicked.connect(self.button_clicked)
        
        self.forgot_password_label = QLabel(self.tr("Forgot password?"), alignment=Qt.AlignCenter)
        self.forgot_password_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        lay = QVBoxLayout(self)
        lay.setSpacing(0)
        lay.addWidget(self.image_label)
        lay.addWidget(self.login_label)
        lay.addWidget(self.email_username_lineedit)
        lay.addWidget(self.password_lineedit)
        lay.addWidget(self.enter_button)
        lay.addWidget(self.forgot_password_label)
        
        # я не знаю, что вам надо будет передавать в дополнительный поток
        self.someUserList = []                                       # Какой-то список
        self.someOtherList = []                                      # Какой-то список
        
        self.loader_file = QMovie("img/Fo2BxBK.gif")
        self.loader_file.start()
        self.loader_label = QLabel(self) 
        self.loader_label.setMovie(self.loader_file)
        self.loader_label.adjustSize()
        self.loader_label.hide()
        
    def button_clicked(self):
        self.enter_button.setDisabled(True)
        if not self.email_username_lineedit.text() or not self.password_lineedit.text():
            msg = QMessageBox.warning(self, 'Внимание', 'Заполните все поля!') 
            self.enter_button.setDisabled(False)
            return
        self.loader_label.show()
        overlayLabel = QLabel('<h1 style="color: red">Please wait..<h1>', self.loader_label)
        overlayLabel.move(100, self.loader_label.height()-30)
        overlayLabel.show()

        # я не знаю, что вам надо будет передавать в дополнительный поток.
        # Предположим что передать надо: логин, пароль и какие-то два списка
        self.worker = Thread(self.email_username_lineedit.text(),
                             self.password_lineedit.text(),
                             self.someUserList,
                             self.someOtherList
                            )
        self.worker.dataThread.connect(self.data_validation)
        self.worker.start()   

    def data_validation(self, text):
        self.loader_label.hide()        
        self.enter_button.setDisabled(False)
        if text == 'error':
            msg = QMessageBox.warning(self, 'Внимание', 
                    'Что-то пошло не так!<br>Проверьте правильность написания вводимой информации.')
        else:
            msg = QMessageBox.information(self, 'Внимание', '<h1>successfully</h1>')


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = LoginPage()
    w.resize(320, 480)
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка