Поиск…


Вступление

Progress Bars являются неотъемлемой частью пользовательского интерфейса и помогают пользователям получить представление о времени, оставшемся для данного процесса, который выполняется в графическом интерфейсе. В этом разделе будут рассмотрены основы реализации индикатора выполнения в вашем собственном приложении.

В этом разделе будет легко коснуться QThread и нового механизма сигналов / слотов. Некоторые читатели видят также видение виджетов PyQt5.

При добавлении примеров используйте только встроенные модули PyQt5 и Python для демонстрации функциональности.

Только PyQt5

замечания

Экспериментировать с этими примерами - лучший способ начать обучение.

Базовая панель управления PyQt

Это очень простой индикатор прогресса, который использует только то, что необходимо на минимальном минимуме.

Было бы разумно прочитать весь этот пример до конца.

import sys
import time

from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar, QPushButton)

TIME_LIMIT = 100

class Actions(QDialog):
    """
    Simple dialog that consists of a Progress Bar and a Button.
    Clicking on the button results in the start of a timer and
    updates the progress bar.
    """
    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle('Progress Bar')
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.progress.setMaximum(100)
        self.button = QPushButton('Start', self)
        self.button.move(0, 30)
        self.show()

        self.button.clicked.connect(self.onButtonClick)

    def onButtonClick(self):
        count = 0
        while count < TIME_LIMIT:
            count += 1
            time.sleep(1)
            self.progress.setValue(count)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    sys.exit(app.exec_())

Панель выполнения сначала импортируется так, как from PyQt5.QtWidgets import QProgressBar

Затем он инициализируется, как и любой другой виджет в QtWidgets

Метод line self.progress.setGeometry(0, 0, 300, 25) определяет положения x,y в диалоговом окне, ширину и высоту индикатора выполнения.

Затем мы перемещаем кнопку с помощью .move() на 30px вниз, чтобы между двумя виджетами был пробел в 5 5px .

Здесь self.progress.setValue(count) используется для обновления прогресса. Установка максимального значения с использованием .setMaximum() также автоматически рассчитает значения для вас. Например, если максимальное значение установлено TIME_LIMIT 50, тогда как TIME_LIMIT равно 100, он будет TIME_LIMIT от 0 до 2 до 4 процентов вместо 0 к 1 к 2 в секунду. Вы также можете установить минимальное значение, используя .setMinimum() заставляя индикатор выполнения начинаться с заданного значения.

Выполнение этой программы приведет к созданию графического интерфейса, подобного этому.

Диалог «Прогресс-бар» не отвечает

Как вы можете видеть, графический интерфейс будет определенно зависеть и не реагировать, пока счетчик не встретит условие TIME_LIMIT . Это связано с тем, что time.sleep заставляет ОС полагать, что программа застряла в бесконечном цикле.

QThread

Итак, как мы преодолеем эту проблему? Мы можем использовать класс потоков, который предоставляет PyQt5.

import sys
import time

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar, QPushButton)

TIME_LIMIT = 100

class External(QThread):
    """
    Runs a counter thread.
    """
    countChanged = pyqtSignal(int)

    def run(self):
        count = 0
        while count < TIME_LIMIT:
            count +=1
            time.sleep(1)
            self.countChanged.emit(count)

class Actions(QDialog):
    """
    Simple dialog that consists of a Progress Bar and a Button.
    Clicking on the button results in the start of a timer and
    updates the progress bar.
    """
    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle('Progress Bar')
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.progress.setMaximum(100)
        self.button = QPushButton('Start', self)
        self.button.move(0, 30)
        self.show()

        self.button.clicked.connect(self.onButtonClick)

    def onButtonClick(self):
        self.calc = External()
        self.calc.countChanged.connect(self.onCountChanged)
        self.calc.start()

    def onCountChanged(self, value):
        self.progress.setValue(value)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    sys.exit(app.exec_())

Давайте разложим эти изменения.

from PyQt5.QtCore import QThread, pyqtSignal

Эта строка импортирует Qthread которая представляет собой реализацию PyQt5 для разделения и запуска некоторых частей (например, функций, классов) программы в фоновом режиме (также известна как многопоточность). Эти части также называются нитями. Все программы PyQt5 по умолчанию имеют основной поток, а другие (рабочие потоки) используются для выгрузки дополнительных трудоемких и трудоемких задач в фоновом режиме, сохраняя при этом основную программу.

Второй импорт pyqtSignal используется для отправки данных (сигналов) между рабочим и основным потоками. В этом случае мы будем использовать его, чтобы сообщить основному потоку обновить индикатор выполнения.

Теперь мы переместили цикл while для счетчика в отдельный класс External .

class External(QThread):
    """
    Runs a counter thread.
    """
    countChanged = pyqtSignal(int)

    def run(self):
        count = 0
        while count < TIME_LIMIT:
            count +=1
            time.sleep(1)
            self.countChanged.emit(count)

QThread мы по существу преобразуем External в класс, который можно запускать в отдельном потоке. Темы могут также запускаться или останавливаться в любое время, добавляя к ним преимущества.

Здесь countChanged - текущий прогресс, а pyqtSignal(int) сообщает рабочему потоку, что передаваемый сигнал имеет тип int . Хотя self.countChanged.emit(count) просто посылает сигнал на любые соединения в основном потоке (обычно он может использоваться для связи с другими рабочими потоками).

def onButtonClick(self):
        self.calc = External()
        self.calc.countChanged.connect(self.onCountChanged)
        self.calc.start()

def onCountChanged(self, value):
    self.progress.setValue(value)

Когда нажимается self.onButtonClick , запускается self.onButtonClick , а также запускает поток. Нить начинается с .start() . Следует также отметить, что мы подключили сигнал self.calc.countChanged мы создали ранее, к методу, используемому для обновления значения индикатора выполнения. При каждом обновлении параметра External::run::count значение int также отправляется в onCountChanged .

Именно так GUI мог бы следить за внесением этих изменений.

Панель выполнения QThread

Он также должен чувствовать себя намного более отзывчивым и не замерзнет.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow