pyqt5
Введение в бары прогресса
Поиск…
Вступление
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 мог бы следить за внесением этих изменений.
Он также должен чувствовать себя намного более отзывчивым и не замерзнет.