Асинхронное программирование в PyQt5 python

Я изучаю библиотеку PyQt5 и Telrgram Client Api (telethone),
написал простенькую программу с дизайном, которая проверяет активную сессию.

Но вопрос более о выводе чем о проверке.
Программа сперва зависает, а после выводит статус всех аккаунтов.

Как сделать чтобы - программа не зависала и по ходу проверки выводила статус подключения одного аккаунта и т.д.

Сейчас она зависает и выводит статус сразу всех.

main.py

#include - telethone
from telethon.sync import TelegramClient, events
from telethon import connection
#GUI
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QLabel
#systems
import asyncio
import sys
import os
from os import path

#создания интерфейса

class Ui_MainWindow(object): 
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(412, 230)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.labelnew = QLabel(self.centralwidget)
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setEnabled(True)
        self.labelnew.setGeometry(QtCore.QRect(0, 30, 211, 50))
        self.label.setGeometry(QtCore.QRect(0, 10, 411, 20))
        font = QtGui.QFont()
        font.setPointSize(14)
        self.label.setFont(font)
        self.label.setTabletTracking(False)
        self.label.setAcceptDrops(False)
        self.label.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.label.setAutoFillBackground(False)
        self.label.setStyleSheet("color:rgb(208, 208, 208);")
        self.label.setTextFormat(QtCore.Qt.PlainText)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setWordWrap(False)
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(-4, -8, 421, 250))
        self.label_2.setStyleSheet("background-color:black;")
        self.labelnew.setStyleSheet("color:white;")
        self.label_2.setObjectName("label_2")
        self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(-1, 39, 421, 181))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.label_2.raise_()
        self.label.raise_()
        self.verticalLayoutWidget.raise_()
        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        self.account_testing()
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(_translate("MainWindow", "Account Connactions"))

#функция проверки аккаунтов

    def account_testing(self):
        accounts_files = self.get_files()
        for account in accounts_files:
            client = TelegramClient(f"data/session/{account}.session" , 1 , "default")
            client.connect()
            label = QLabel(self.verticalLayoutWidget)
            if not client.is_user_authorized():
                label.setStyleSheet("padding-left:15px;color:rgb(255, 66, 69);")
                label.setText("Accaount is not Connected")
            else:
                label.setText("Accaount is Connected")
                label.setStyleSheet("padding-left:15px;color:rgb(95, 255, 92);")
            self.verticalLayout.addWidget(label)

#функция получения файлов сессий

    def get_files(self):
        _path = "data/session/"
        filelist = []
        for root , dirs , files , in os.walk(_path):
            for file in files:
                if(file.endswith(".session")):
                    filelist.append( path.splitext( os.path.join(file))[0])
        return filelist

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Я так думаю надо работать с асинхронными методами, но как подключить и как это сделать я не знаю. Пробовал найти разную информации, но ничего не работает.


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

Автор решения: arnold

Должно помочь:

# include - telethone
from telethon.sync import TelegramClient, events
from telethon import connection
# GUI
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QLabel
# systems
import asyncio
import sys
import os
from os import path
import threading


# создания интерфейса

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(412, 230)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.labelnew = QLabel(self.centralwidget)
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setEnabled(True)
        self.labelnew.setGeometry(QtCore.QRect(0, 30, 211, 50))
        self.label.setGeometry(QtCore.QRect(0, 10, 411, 20))
        font = QtGui.QFont()
        font.setPointSize(14)
        self.label.setFont(font)
        self.label.setTabletTracking(False)
        self.label.setAcceptDrops(False)
        self.label.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.label.setAutoFillBackground(False)
        self.label.setStyleSheet("color:rgb(208, 208, 208);")
        self.label.setTextFormat(QtCore.Qt.PlainText)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setWordWrap(False)
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(-4, -8, 421, 250))
        self.label_2.setStyleSheet("background-color:black;")
        self.labelnew.setStyleSheet("color:white;")
        self.label_2.setObjectName("label_2")
        self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(-1, 39, 421, 181))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.label_2.raise_()
        self.label.raise_()
        self.verticalLayoutWidget.raise_()
        MainWindow.setCentralWidget(self.centralwidget)
        #####################################################
        threading.Thread(target=self.account_testing).start()
        #####################################################
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(_translate("MainWindow", "Account Connactions"))

    # функция проверки аккаунтов

    def account_testing(self):
        accounts_files = self.get_files()
        for account in accounts_files:
            client = TelegramClient(f"data/session/{account}.session", 1, "default")
            client.connect()
            label = QLabel(self.verticalLayoutWidget)
            if not client.is_user_authorized():
                label.setStyleSheet("padding-left:15px;color:rgb(255, 66, 69);")
                label.setText("Accaount is not Connected")
            else:
                label.setText("Accaount is Connected")
                label.setStyleSheet("padding-left:15px;color:rgb(95, 255, 92);")
            self.verticalLayout.addWidget(label)

    # функция получения файлов сессий

    def get_files(self):
        _path = "data/session/"
        filelist = []
        for root, dirs, files, in os.walk(_path):
            for file in files:
                if (file.endswith(".session")):
                    filelist.append(path.splitext(os.path.join(file))[0])
        return filelist


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
→ Ссылка
Автор решения: S. Nick

Я не могу проверить ваш пример, но один из вариантов предложу, попробуйте.

Мне не приглянулась ваша форма Ui_MainWindow(object) и предложу свою.

НИКОГДА НЕ ИЗМЕНЯЙТЕ код, сгенерированный Qt Designer, НИКОГДА.
Создайте другой класс, который наследуется от соответствующего виджета, и используйте созданный класс для его заполнения.

Тяжелые задачи должны выполняться в отдельном потоке.

import sys
import os
from os import path
#systems
#import asyncio

#include - telethone
from telethon.sync import TelegramClient, events
from telethon import connection

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QLabel


class WorkThread(QtCore.QThread):
    threadSignal = QtCore.pyqtSignal(str, bool)
    finished = QtCore.pyqtSignal(str)
    
    def __init__(self, accounts_files):
        super().__init__()
        self.accounts_files = accounts_files

    def run(self):
        for account in self.accounts_files:
            client = TelegramClient(f"data/session/{account}.session" , 1 , "default")
            client.connect()
            
            if not client.is_user_authorized():
#            if not int(account[-1]) % 2:

                user_authorized = False
            else:
                user_authorized = True

            self.threadSignal.emit(account, user_authorized)
            
            self.msleep(10)             
#            self.msleep(1000)                                 # миллисекунд, имитируем длительную загрузку

        self.finished.emit("Start thread")


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.thread = None
        
        self.centralwidget = QtWidgets.QWidget()
        self.centralwidget.setObjectName("centralwidget")
        self.setCentralWidget(self.centralwidget)
        
        self.label = QtWidgets.QLabel("Account Connactions", 
            self.centralwidget, alignment=QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")

        self.textBrowser = QtWidgets.QTextBrowser()
        self.textBrowser.setObjectName("textBrowser")
        
        self.pushButton = QtWidgets.QPushButton('Start thread')
        self.pushButton.setObjectName("pushButton")
        self.pushButton.clicked.connect(self.go_clicked)

        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
#        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.addWidget(self.label)
        self.verticalLayout.addWidget(self.textBrowser)
        self.verticalLayout.addWidget(self.pushButton, alignment=QtCore.Qt.AlignRight)

    def go_clicked(self):
        if self.thread is None:
            accounts_files = self.get_files()
        
            self.thread = WorkThread(accounts_files)
            self.thread.threadSignal.connect(self.on_threadSignal)
            self.thread.finished.connect(self.thread_finished)
            self.thread.start()
            self.pushButton.setText("Stop thread")
        else:
            self.thread.terminate()
            self.thread = None
            self.pushButton.setText("Start thread")

    # функция получения файлов сессий
    def get_files(self):
        _path = "data/session/"
        self.filelist = []
        for root , dirs , files , in os.walk(_path):
            for file in files:
                if(file.endswith(".session")):
                    self.filelist.append( path.splitext( os.path.join(file))[0])

        return filelist 

#        return [
#            'account1', 'account2', 'account3', 'account4', 
#            'account5', 'account6', 'account7', 'account8',
#        ]         

    def on_threadSignal(self, account, user_authorized):
        cursor = self.textBrowser.textCursor()
        cursor.movePosition(cursor.End)

        if user_authorized:
            cursor.insertHtml(f'''<br><b style="padding-left:15px;color:rgb(95, 255, 92);">
                    {account}: Accaount is Connected, code={user_authorized}
                </b><br>''')            
        else:            
            cursor.insertHtml(f'''<br><b style="padding-left:15px;color:rgb(255, 66, 69);">
                    {account}: Accaount is not Connected, code={user_authorized}
                </b><br>''')
            
        self.textBrowser.ensureCursorVisible()
        
    def thread_finished(self, text):
        self.thread = None
        self.pushButton.setText("Start thread")


StyleSheet = '''
#centralwidget {
    background-color: rgba(35, 135, 135, 122);
} 
#label {
    font-size: 25px;     
} 
#textBrowser {
    background-color: rgba(35, 135, 135, 222);
    font-size: 15px;     
}
#pushButton {
    background-color: rgba(135, 135, 135, 122);
}   
'''
        

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    app.setStyleSheet(StyleSheet)    
    w = MainWindow()
    w.resize(500, 500)
    w.show()
    sys.exit(app.exec_())

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

→ Ссылка