pyqt5
Introducción a las barras de progreso
Buscar..
Introducción
Las barras de progreso son una parte integral de la experiencia del usuario y ayudan a los usuarios a tener una idea del tiempo que queda para un proceso determinado que se ejecuta en la GUI. Este tema tratará los aspectos básicos de la implementación de una barra de progreso en su propia aplicación.
Este tema tratará ligeramente sobre QThread y el nuevo mecanismo de señales / ranuras. También se espera un cierto conocimiento básico de los widgets de PyQt5 de los lectores.
Cuando se agregan ejemplos, solo se utilizan los complementos PyQt5 y Python para demostrar la funcionalidad.
Sólo PyQt5
Observaciones
Experimentar con estos ejemplos es la mejor manera de comenzar a aprender.
Barra de progreso de PyQt básica
Esta es una barra de progreso muy básica que solo usa lo que se necesita como mínimo.
Sería prudente leer todo este ejemplo hasta el final.
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_())
La barra de progreso se importa primero from PyQt5.QtWidgets import QProgressBar
Luego se inicializa como cualquier otro widget en QtWidgets
El self.progress.setGeometry(0, 0, 300, 25)
línea self.progress.setGeometry(0, 0, 300, 25)
define las posiciones x,y
en el cuadro de diálogo y el ancho y alto de la barra de progreso.
Luego movemos el botón usando .move()
en 30px
hacia abajo para que haya un espacio de 5px
entre los dos widgets.
Aquí self.progress.setValue(count)
se usa para actualizar el progreso. Establecer un valor máximo utilizando .setMaximum()
también calculará automáticamente los valores para usted. Por ejemplo, si el valor máximo se establece en 50, dado que TIME_LIMIT
es 100 TIME_LIMIT
de 0 a 2 a 4 por ciento en lugar de 0 a 1 a 2 cada segundo. También puede establecer un valor mínimo usando .setMinimum()
forzando que la barra de progreso comience a partir de un valor dado.
La ejecución de este programa producirá una GUI similar a esta.
Como puede ver, la GUI definitivamente se congelará y no responderá hasta que el contador cumpla con la condición TIME_LIMIT
. Esto se debe a que time.sleep
hace que el sistema operativo crea que el programa se ha atascado en un bucle infinito.
Qhilo
Entonces, ¿cómo superamos este problema? Podemos usar la clase de subprocesos que proporciona 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_())
Vamos a desglosar estas modificaciones.
from PyQt5.QtCore import QThread, pyqtSignal
Esta línea importa Qthread
que es una implementación de PyQt5
para dividir y ejecutar algunas partes (por ejemplo: funciones, clases) de un programa en segundo plano (también conocido como multihilo). Estas partes también se llaman hilos. PyQt5
defecto, todos los programas de PyQt5
tienen un subproceso principal y los otros (subprocesos de trabajo) se utilizan para descargar más tiempo y procesar tareas intensivas en segundo plano mientras se mantiene el funcionamiento del programa principal.
La segunda importación pyqtSignal
se utiliza para enviar datos (señales) entre los procesos de trabajo y los subprocesos principales. En este caso, lo utilizaremos para indicar al subproceso principal que actualice la barra de progreso.
Ahora hemos movido el bucle while para el contador a una clase separada llamada 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
esencialmente estamos convirtiendo External
en una clase que puede ejecutarse en un hilo separado. Los hilos también pueden iniciarse o detenerse en cualquier momento, lo que se suma a sus beneficios.
Aquí countChanged
es el progreso actual y pyqtSignal(int)
le dice al subproceso de trabajo que la señal que se envía es de tipo int
. Mientras que self.countChanged.emit(count)
simplemente envía la señal a cualquier conexión en el subproceso principal (normalmente, también se puede usar para comunicarse con otros subprocesos de trabajo).
def onButtonClick(self):
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
def onCountChanged(self, value):
self.progress.setValue(value)
Cuando se hace clic en el botón, self.onButtonClick
se ejecutará y también iniciará el hilo. El hilo comienza con .start()
. También se debe tener en cuenta que conectamos la señal self.calc.countChanged
que creamos anteriormente al método utilizado para actualizar el valor de la barra de progreso. Cada vez que External::run::count
se actualiza, el valor int
también se envía a onCountChanged
.
Así es como podría verse la GUI después de realizar estos cambios.
También debe sentirse mucho más sensible y no se congelará.