Нужен аналог PyQt QProgressBar

Рейтинг: 1Ответов: 1Опубликовано: 21.05.2023

Я пишу приложение, которое чем-то похоже на discord authy и меня интересует та уползающая шкала вверху экрана.
Я пытался сделать её, используя QProgressBar от PyQt5, но когда приложение запускается, QProgressBar не даёт другим процессам выполняться.

Есть ли способ чем-нибудь его заменить? Желательно на PyQt5.

main.py:

import random
import time
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QWidget, QApplication, QLabel, 
QVBoxLayout, QProgressBar, QPushButton
import pyperclip


def codegen():
    letters = "abcdefghijklmnopqrstuvwxyz"
    code = ""
    for i in range(10):
        number = random.randint(0, 9)
        code += str(number)
    code += ':'
    for i in range(15):
        ln = random.randint(0, 1)
        if ln == 0:
            ud = random.randint(0, 1)
            letter = letters[random.randint(0, 25)]
            if ud == 0:
                letter = letter.upper()
        code += letter
        if ln == 1:
            number = random.randint(0, 9)
            code += str(number)
    return code


def codecopy():
    pyperclip.copy(w.title.text())


class Window(QWidget):
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)

        self.pbar = QProgressBar()
        self.title = QLabel()
        self.copy = QPushButton('скопировать')

        layout = QVBoxLayout(self)
        layout.addWidget(self.title)
        layout.addWidget(self.pbar)
        layout.addWidget(self.copy)

        QTimer.singleShot(3000, self.start)
        self.copy.clicked.connect(codecopy)

    def decrease(self):
        for i in range(101):
            time.sleep(0.05)
        
            self.pbar.setValue(100 - i)
            self.refresh()

    def refresh(self):
        if self.pbar.value() <= 0:
            self.pbar.setValue(100)
            self.title.setText(codegen())
            self.decrease()

    def start(self):
        self.pbar.setValue(100)
        self.title.setText(codegen())
        self.decrease()
        codecopy()


app = QApplication([])
w = Window()

w.show()
app.exec_()

Ответы

▲ 1Принят

Нельзя использовать time.sleep(...) в основном потоке, это замораживает интерфейс.

Я не совсем понимаю когда вы собираетесь заканчивать цикл.

Для решения вашей задачи, вам нужен дополнительный поток и выглядит это может примерно так:

import random
#import time
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QApplication, QLabel, \
    QVBoxLayout, QProgressBar, QPushButton, QMessageBox
import pyperclip


def codegen():
    letters = "abcdefghijklmnopqrstuvwxyz"
    
    code = ""
    for i in range(10):
        number = random.randint(0, 9)
        code += str(number)
        
    code += ':'
    for i in range(15):
        letter = ''                                                  # +
        ln = random.randint(0, 1)
        if ln == 0:
            ud = random.randint(0, 1)
            letter = letters[random.randint(0, 25)]
            if ud == 0:
                letter = letter.upper()
                
        code += letter
        if ln == 1:
            number = random.randint(0, 9)
            code += str(number)
    return code


def codecopy():
    pyperclip.copy(w.title.text())
    QMessageBox.information(None, "Инфо", "title скопированы в буфер обмена!") #
            
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
class Worker(QThread):
    progressChanged = pyqtSignal(int)

    def run(self):
        print(f'def run(self):') #
#    def decrease(self):
        for i in range(101):
            self.msleep(50)
#            self.pbar.setValue(100 - i)
            self.progressChanged.emit(100 - i)

#            self.refresh()
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

class Window(QWidget):
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)

        self.pbar = QProgressBar()
        self.title = QLabel()
        self.button_copy = QPushButton('скопировать')

        layout = QVBoxLayout(self)
        layout.addWidget(self.title)
        layout.addWidget(self.pbar)
        layout.addWidget(self.button_copy)

        QTimer.singleShot(3000, self.start)
        self.button_copy.clicked.connect(codecopy)


        self.worker = Worker()                                       # +++
        self.worker.progressChanged.connect(self.updateProgress)     # +++

    def updateProgress(self, v):                                     # +++
        self.pbar.setValue(v)
        self.refresh()
        
    def refresh(self):
        if self.pbar.value() <= 0:
            self.pbar.setValue(100)
            self.title.setText(codegen())
#            self.decrease() 
            self.worker.start()
   
    def start(self):
        self.pbar.setValue(100)
        _codegen = codegen()
        print(f'_codegen = {_codegen}') #
        self.title.setText(_codegen)
        
        self.worker.start()                                          # +++
        
# ?        self.decrease()
        codecopy()


if __name__ == '__main__':
    import sys
    
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

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