Saltar al contenido

Curso de creación de GUIs con Qt. Capítulo 06: Splash Screen

Vamos a seguir evolucionando hacia hacer GUIs cada vez más sofisticados. En este capítulo describo como crear una pantalla inicial que sale previamente a la carga de la aplicación principal y que permite ir informando sobre como va el proceso de arranque de la misma.

Índice:

[Los materiales para este capítulo los podéis descargar de aquí]

[INSTALACIÓN] Si todavía no has pasado por el inicio del curso, donde explico cómo poner a punto todo, ahora es un buen momento para hacerlo y después podrás seguir con esta nueva receta.

Habéis visto muchas veces el tipo de ventanitas que vamos a crear hoy. Su nombre en inglés es Splash Screen y en castellano no tengo ni idea de cómo se puede llamar. A continuación os dejo unos cuantos enlaces con ejemplos para que quede claro a lo que nos estamos refiriendo:

Esta ventana no es más que una ventana que sale al principio de ejecutar la aplicación y que permite que la aplicación realice una serie de cosas antes de estar funcional. Por ejemplo, imagínate que cuando haces doble click sobre la aplicación X esta tiene que conectarse a una base de datos y cargar una serie de campos antes de que podamos empezar a usarla. Esto puede llevar algún tiempo. Si no avisamos al usuario de que se está cargando después de que haya pulsado el doble click puede acabar pensando que algo va mal y que la aplicación no responde. Para evitar esto se suele mostrar el Splash Screen que puede dar cierta información al usuario de como va el arranque. Este Splash Screen es lo primero que se carga antes de que la aplicación principal esté totalmente funcional.

Vamos a partir del último código que usamos en el anterior capítulo:

'''
Curso de creación de GUIs con Qt5 y Python

Author: Kiko Correoso
Website: pybonacci.org 
Licencia: MIT
'''

import os
os.environ['QT_API'] = 'pyside2'
import sys
from pathlib import Path

from qtpy.QtWidgets import QApplication, QMainWindow
from qtpy.QtGui import QIcon

class MiVentana(QMainWindow):
    def __init__(self):
        super().__init__()
        self._create_ui()

    def _create_ui(self):
        self.resize(500, 300)
        self.move(0, 0)
        self.setWindowTitle('Hola, QMainWindow')
        ruta_icono = Path('.', 'imgs', 'pybofractal.png')
        self.setWindowIcon(QIcon(str(ruta_icono)))
        self.statusBar().showMessage('Ready')
        self.show()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    w = MiVentana()
    sys.exit(app.exec_())

Imagen

Podemos usar una imagen para el fondo del Splash Screen. Vamos a usar una con licencia permisiva. En este caso voy a usar la que se encuentra en este enlace.

La podéis descargar y guardar en una carpeta que se llame imgs/ con el nombre splashscreen_background.jpg. La carpeta debe estar en el mismo sitio donde esté nuestro fichero .py.

Si habéis descargado el repositorio, simplemente deberéis ir a la carpeta apps/06-SplashScreen para ejecutar el programa desde allí.

Al anterior código le vamos a añadir una serie de cosas que destacaremos, como siempre, usando el comentario ## NUEVA LÍNEA en cada línea nueva de código y comentaremos más tarde:

'''
Curso de creación de GUIs con Qt5 y Python

Author: Kiko Correoso
Website: pybonacci.org 
Licencia: MIT
'''

import os
os.environ['QT_API'] = 'pyside2'
import sys
from pathlib import Path
import time ## NUEVA LÍNEA

from qtpy.QtCore import Qt ## NUEVA LÍNEA
from qtpy.QtWidgets import QApplication, QMainWindow, QSplashScreen ## NUEVA LÍNEA
from qtpy.QtGui import QIcon, QPixmap ## NUEVA LÍNEA

class MiVentana(QMainWindow):
    def __init__(self):
        super().__init__()
        self._create_ui()

    def _create_ui(self):
        self.resize(500, 300)
        self.move(0, 0)
        self.setWindowTitle('Hola, QMainWindow')
        ruta_icono = Path('.', 'imgs', 'pybofractal.png')
        self.setWindowIcon(QIcon(str(ruta_icono)))
        self.statusBar().showMessage('Ready')
        self.show()

if __name__ == '__main__':

    app = QApplication(sys.argv)

    # Crea y muestra el splash screen
    path = Path('imgs', 'splashscreen_background.jpg') ## NUEVA LÍNEA
    splash_pix = QPixmap(str(path)) ## NUEVA LÍNEA
    splash = QSplashScreen( ## NUEVA LÍNEA
        splash_pix, ## NUEVA LÍNEA
        Qt.WindowStaysOnTopHint ## NUEVA LÍNEA
    ) ## NUEVA LÍNEA
    splash.setEnabled(False) ## NUEVA LÍNEA
    splash.show() ## NUEVA LÍNEA

    # Esto es un simple contador/temporizador para mostrar en pantalla
    # el splash screen. En el futuro haremos que esto sea más útil.
    for i in range(0, 5): ## NUEVA LÍNEA
        msg = ( ## NUEVA LÍNEA
            '<h1><font color="yellow">' ## NUEVA LÍNEA
             f'Listo en {5-i}s' ## NUEVA LÍNEA
             '</font></h1>' ## NUEVA LÍNEA
        ) ## NUEVA LÍNEA
        splash.showMessage( ## NUEVA LÍNEA
            msg, ## NUEVA LÍNEA
            int(Qt.AlignBottom) | int(Qt.AlignHCenter),  ## NUEVA LÍNEA
            Qt.black  ## NUEVA LÍNEA
        ) ## NUEVA LÍNEA
        time.sleep(1) ## NUEVA LÍNEA
        app.processEvents() ## NUEVA LÍNEA

    w = MiVentana()
    splash.finish(w) ## NUEVA LÍNEA
    sys.exit(app.exec_())

Muchos ## NUEVA LÍNEA. Explico un poco el código nuevo y luego vemos cómo hacerlo funcionar.


from qtpy.QtCore import Qt

Qt es un espacio de nombres con información útil que Qt (el framework) usa internamente en todo su código. Luego vemos lo que usamos de este espacio de nombres.


from qtpy.QtWidgets import QApplication, QMainWindow, QSplashScreen

Importamos la clase QSplashScreen. Esta clase no es más que una nueva clase que, nuevamente, hereda de QWidget, como QMainWindow, y que tiene alguna nueva funcionalidad para que creemos la Splash Screen para nuestra aplicación.


from qtpy.QtGui import QIcon, QPixmap

Importamos la clase QPixmap. La usamos únicamente para añadir un mapa de píxeles (nuestra imagen) a la ventana del Splash Screen. Luego vemos cómo la estamos usando.


    # Crea y muestra el splash screen
    path = Path('imgs', 'splashscreen_background.jpg')
    splash_pix = QPixmap(str(path))
    splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
    splash.setEnabled(False)
    splash.show()

En esta parte ya hacemos uso de algunas de las nuevas cosas que hemos importado:

  • path simplemente guarda la ruta a la imagen que vamos a usar de fondo. Esto no es código relacionado con Qt en sí.
  • splash_pix es una instancia de QPixmap. Nos guarda la imagen en una forma que entiende Qt.
  • splash es la instancia de QSplashScreen. Recibe la imagen en la forma en que la entiende Qt, splash_pix, y, además, le pasamos una marca o flag, Qt.WindowStaysOnTopHint, que le indica que debe permanecer delante del resto de ventanas en el escritorio.
  • splash.setEnabled(False) nos permite decirle al programa que no esté activo a eventos que le podamos pasar, como un click, ya que podemos tener algún efecto indeseado.
  • splash.show(), mediante este método mostramos el Splash Screen en pantalla.

Nuestro Splash Screen estará en pantalla hasta que le digamos. Para que se vea un rato voy a usar un temporizador y vamos a actualizar los mensajes que muestra la pantalla.


    # Esto es un simple contador/temporizador para mostrar en pantalla
    # el splash screen. En el futuro haremos que esto sea más útil.
    for i in range(0, 5):
        msg = (
            '<h1><font color="yellow">'
             f'Listo en {5-i}s'
             '</font></h1>'
        )
        splash.showMessage(
            msg,
            int(Qt.AlignBottom) | int(Qt.AlignHCenter),
            Qt.black
        )
        time.sleep(1)
        app.processEvents()

Aquí vamos a actualizar el mensaje que muestra el Splash Screen en pantalla. La clase QSplashScreen dispone de varios métodos para mostrar información en la pantalla. Podríamos añadir una barra de progreso, leer del programa a medida que va cargando cosas,…, pero lo vamos a mantener simple ahora usando un temporizador

Hacemos un bucle que vaya de 0 a 4 porque contaremos una serie de segundos. Dentro de este bucle:

  • Creamos el mensaje que queremos monstrar guardado en msg. Como veis, uso HTML ya que está permitido.
  • Usamos el método showMessage de la clase QSplashScreen para escribir el mensaje en la ventanita de bienvenida/Carga inicial. Le pasamos el mensaje, la posición del mensaje ((*) int(Qt.AlignBottom) | int(Qt.AlignHCenter)) y el color (Qt.black). En este caso, el color no tendrá efecto porque estamos pasando un código HTML y se hace caso al código HTML.
  • Dejamos que la aplicación duerma 1 segundo usando time.sleep.
  • Llamamos al método processEvents de la clase QApplication que nos permite ir procesando cosas que puedan estar pendientes antes de poder continuar. En este caso no estamos haciendo nada especial pero no hace daño meterlo.

Del bloque que acabamos de comentar vamos a hacer varias variaciones para que podáis ver en vivo como afectan estas variaciones. Por ejemplo, con el tema del color en el mensaje, podéis eliminar el código HTML y pasarle el color blanco, por ejemplo, para que véais cómo se verá ahora el mensaje:

        # ...
        msg = f'Listo en {5 - i} s'
        splash.showMessage(
            msg,
            int(Qt.AlignBottom) | int(Qt.AlignHCenter),
            Qt.white
        )
        # ...

Por otra parte, había dejado un asterisco (*) al lado de int(Qt.AlignBottom) | int(Qt.AlignHCenter) para ver si puedo explicar un poco mejor lo que hace eso. Ahí estamos definiendo la alineación del mensaje en la pantalla. Estamos usando el operador bitwise or, |, y el espacio de nombres de Qt. En ese espacio de nombres se definen varias posiciones como AlignLeft, AlignTop,… Mediante combinaciones de ellas podemos posicionar el mensaje donde nos interese. Qt recibirá un entero y sabrá que ese entero significará, por ejemplo, arriba a la derecha, centrado en medio,…

Por ejemplo, según la documentación:

  • AlignLeft tiene el valor 0x0001 que en binario será 00000001.
  • AlignVCenter tiene el valor 0x0080 que en binario será 10000000.

Si queremos que salga alineado a la izquierda y centrado en altura podemos combinar ambas con el operador | y nos devolverá, en binario, 10000001, que en decimal será 129.

Usando los valores del espacio de nombres será más sencillo que tener que aprender todos estos números y sabiendo que los podemos combinar como he indicado podemos llegar a tener un gran control sobre lo que queremos mostrar.

Después de este breve inciso podéis cambiar el valor int(Qt.AlignBottom) | int(Qt.AlignHCenter) por los siguientes valores para ver el efecto de todo esto:

  • int(Qt.AlignCenter)
  • int(Qt.AlignRight) | int(Qt.AlignTop)
  • int(Qt.Alignleft) | int(Qt.AlignBottom)

Sigo comentando el código que nos queda una última línea nueva:


    splash.finish(w)

En esta línea usamos el método finish de QSplashScreen para que se cierre la ventana de inicio en el momento que la ventana principal, w, esté lista.

Si guardáis el código que hemos comentado en un programa que se llame main00.py y en la misma carpeta donde está este programa tenéis una carpeta imgs/ con la imagen llamada splashscreen_background.jpg lo podréis ejecutar usando la línea de comandos (o Anaconda Prompt en Windows) de la siguiente forma:

python main00.py

Si todo funciona correctamente, deberéis de ver una ventanita parecida a la siguiente:

Si cambiáis el mensaje para que no use HTML y use el color blanco, como hemos comentado más arriba, se debería ver así (se ve muy pequeñito abajo):

Si cambiáis la alineación podéis hacer que el mensaje aparezca en otros lados. Un ejemplo con el mensaje abajo a la izquierda se debería ver así:

Y aquí lo dejamos hoy. En el próximo capítulo seguiremos añadiendo cosas a nuestra GUI.

3 comentarios en «Curso de creación de GUIs con Qt. Capítulo 06: Splash Screen»

    1. Sin ver el código que estás usando no tengo ni idea de qué puede estar fallando pero supongo que será que la ruta que estás usando es incorrecta.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

nine + 1 =

Pybonacci