Heey! Ahora si se acabo la consolita cutre, vamos a ver algo un poco más bonito!! Aprenderemos a crear aplicaciones gráficas usando PyQt y vamos a aplicar lo que aprendimos en el Modulo 1 y Modulo 2. Trataremos de que sea fácil y preciso explicando cada parte de código en «criollo» como siempre para que aprendas de verdad y no te estanques!. Vamos a conocer un poco PyQt para luego instalar y sacar a volar una ventana sencilla, con un label y un botón bastante chulito!
¿Qué es PyQt?
Pyqt como dijimos es un binding de la biblioteca gráfica de QT para el lenguaje de programación Python. Nos permitirá desarrollar aplicaciones con un entorno gráfico agradable.
Este entorno de desarrollo tiene algunas ventajas y desventajas que debemos destacar:
Ventajas de utilizar Pyqt:
- Completo conjunto de elementos (Listados, árboles, grillas, etc.))
- Flexible y potente control del comportamiento de la interface.
- Rápido y de apariencia nativa (las últimas versiones utilizan apariencia nativa en windows))
- Se puede separar el diseño de la interface, pero utiliza un compilador Pyuic para crear las clases.
- Arquitectura opcional para Modelo/Vista de las tablas, listas y árboles.
Desventajas de utilizar Pyqt:
- No viene pre-instalado con Python.
- Algo más complejo de aprender que otras GUI’s.
- No es del todo «Pythonico». En ocasiones emerge la implementación en C++ subyacente, teniendo que hacer cast entre tipos de datos (conversión de tipos de datos.), etc.
- El prefijo Qt/Q (QtGUI, QWidget, QAplicattion) hace que nuestro código sea menos «Pythonico».)
Pero todas estas desventajas no nos importan, lo vamos a instalar igual!. Venga a ello!
Tutorial: Instalar PyQt 5 y QtDesigner
Primero lo primero dijo mi primo!. Para instalar PyQt de una manera más sencilla necesitamos PIP (una utilidad de línea de comandos que permite instalar, reinstalar o desinstalar paquetes PyPI con un comando simple y directo: «pip»)
Instalando PIP + PyQt5 en Linux (terminal):
Por supuesto primero debemos saber que versión de Python tenemos instalada, en caso de tener ambas como en el mío instala
Aquí te dejo los comandos:
#Detectar version de Python (utiliza uno u otro): python --version python3 --version ################ Instalar PIP ################ #Python 2.x sudo apt-get install python-pip #Python 3.x sudo apt-get install python3-pip #Actualizar PIP una vez instalado pip install -U pip ################ Instalar PyQt5.- ################ pip install pyqt5 #Y eso es todo!
Instalando PIP + PyQt5 en Windows (cmd):
Para instalar PIP en Windows primero debemos saber que versión de Python tenemos instalada, luego procederemos a descargar de las URL que te dejo debajo el script de PIP llamado «get-pip.py» (es un script de Python) y a ejecutarlo.
#Detectar version de Python (utiliza uno u otro): python --version python3 --version ################ Instalar PIP ################ #Python 2.x #Descarga el siguiente archivo: https://bootstrap.pypa.io/get-pip.py #Python 3.x #Descarga el siguiente archivo: https://bootstrap.pypa.io/3.2/get-pip.py #Posicionate en la carpeta donde lo guardaste. Puedes utilizar el comando "cd" para #moverte por los directorios en Windows, una vez estés allí ejecuta, según tu versión: #Python 2.x: python get-pip.py #Python 3.x: python3 get-pip.py ################ Instalar PyQt5.- ################ pip install pyqt5 #Y eso es todo!
Nos preguntara si deseamos proceder y escribimos «Y» e instalamos. Una vez finalizada la instalación podemos abrir QtDesigner:
En linux desde el menú o en la consola:
designer
Bonito! Sublime!
-Ahora, que coño es esto?
Pues QtDesigner nos va a permitir diseñar el entorno gráfico de nuestro programa a través de Widgets (botones, cuadros de texto, checkbox, etc.) que puedes arrastrar y soltar, redimensionar, en fin, pura comodidad. Luego podrás exportarlo a un archivo .ui (User interface). El cual mas tarde vamos a pasar a .py (Archivo de Python)
Venga a ello, empecemos de una vez!
Nuestra primera ventana en Pyqt 5
Primeramente debemos crear una ventana (Main Window), con un tamaño por defecto, ya luego la dimensionaremos a nuestro gusto!
Veremos algo como esto, así que vamos a dimencionarla a nuestro gusto y agregaremos dos Widget’s. Un Label (Texto) y un botón (Push Button), ambos los vamos a dejar por defecto!:
Si deseas puedes ver una vista previa de tu ventana, tanto en tu SO actual como por ejemplo en Windows o Linux. Así:
Exportando nuestra ventana .ui a .py
Bien ahora vamos a guardar nuestro diseño en un archivo .UI para luego pasarlo a uno de Python que nos permita trabajar el código. Pues esto solo es la gráfica, si presionas ese botón, no pasara ni papa. Recuerda guardar el archivo donde te quede mas fácil para acceder luego desde la consola. En mi caso simplemente lo guarde en el escritorio. Solo vas a Archivo > Guardar Como.. Y le das un nombre ademas de especificar la ubicación.
Una vez que tienes tu archivo.UI vamos a convertirlo a .py. Para eso vamos a la consola y mediante el siguiente comando lo convertimos. (Recuerda que en la consola debes posicionarte donde se encuentra el archivo primero.)
pyuic5 -x miventana.ui -o miventana_ui.py
Tu archivo debe tener el nombre con el que lo has guardado, así que cambia en el comando por tu nombre y ejecutas. Deberías ver inmediatamente que aparece un archivo .py
Si ejecutas este archivo .py como normalmente lo hacemos vas a ver que aparece tu ventana, pero obviamente como dijimos, no hace nada.
El código Python de nuestra ventana Pyqt 5
Ahora con nuestro IDE vamos a abrir ese archivo haber que contiene, en mi caso utilizo Geany. Así que al abrirlo vemos el siguiente código:
Vamos a detenernos a leerlo, aunque suene extraño. Es muy importante que te detengas a mirarlo, observar con paciencia el código.
En la primera linea vemos lo siguiente:
from PyQt5 import QtCore, QtGui, QtWidgets
Esta linea nos esta diciendo que se importa desde PyQt5 el QtCore que vendría a ser el «núcleo» de Pyqt. Siguiendo por QtGUI (Interfaz de usuario) y QtWidgets (Los widgets). Estas son las librerías que necesita Python para mostrar el entorno gráfico, sin ellas no seria posible. Si no entiendes esta parte del codigo pegale un vistazo a esta entrada sobre módulos y librerías en python.
Sigamos! Estoy seguro que reconoces que lo que viene luego es una clase que hereda de object llamada UI_MainWindow. Ahora ves la importancia de aprender las clases en python y programacion orientada a objetos. Si logras comprender el código, al menos un poco es que estas bien parado y puedes continuar 😛
Lo que sigue son métodos y atributos que definen la estética de la ventana y sus Widget’s como por ejemplo el tamaño del botón y dimensiones de la ventana, su label, etc. Vamos a estudiar linea por linea, comentándolas. Venga que tengo unas ganas!
Examinando y comprendiendo el código
Bien para comenzar a entender un poco el código vamos a comenzar por el condicional puesto que en las lineas anteriores esta importando módulos, librerías y declarando una clase que hereda de object con dos métodos (setupUi, retranslateUi).
Condicional __name__ == __main__
if __name__ == "__main__": #Condicional que comprueba si ha sido ejecutado import sys #Importa el módulo Sys app = QtWidgets.QApplication(sys.argv) #crea un objeto de aplicación (Argumentos de sys) MainWindow = QtWidgets.QMainWindow() #Instancia ui = Ui_MainWindow() #instancia ui.setupUi(MainWindow) #Llama al Metodo setupUI con MainWindow como argumento MainWindow.show() #Método que muestra la ventana sys.exit(app.exec_()) #Inicia el ciclo de eventos y bloquea hasta que se cierre la aplicación
Como vemos en la primera linea existe un condicional que esta verificando si el atributo __name__ es igual a «__main__». Esto sirve para evitar que nuestra ventana aparezca también si se importase como un módulo:
Todo modulo o código de python tiene estos atributos donde __name__ varia depende de como se lo este utilizando. Si fue ejecutado por ejemplo desde el terminal, o si fue importado como un módulo. En este caso el condicional comprueba mediante el operador de comparación (==) si se paso el parámetro «__main__» para __name__. Lo que significaría que fue ejecutado. Y entonces al cumplirse este condicional se ejecuta el código debajo.
Por el contrario si nuestro archivo «.py» fuese importado como un módulo esta condición no se cumpliría y no se ejecutaría el código debajo del condicional. Porque el atributo __name__ en ese caso recibiría el nombre del archivo «.py» Me explico?
Cuando llamamos un archivo como módulo en otro: El atributo __name__ recibe como parámetro su mismo nombre.
Cuando ejecutamos un archivo como programa principal: El atributo __name__ recibe como parámetro «__main__»
Import sys
Ahora cumpliéndose este condicional sigue con «import sys».
Sys es un módulo de sistema que nos permite trabajar con el interprete. Es decir, que este módulo carga las variables y funcionalidades relacionadas con el interprete. Y es utilizado en nuestro código en la ultima linea «sys.exit(app.exec_())» el cual fuerza la salida del interprete. Pero le esta brindando como argumento «app.exec()» el cual ejecuta un bucle principal que funciona hasta que el programa es cerrado, en lo cual sys.exit() devolverá un código de estado. Este «estado» indica si se han recibido códigos de error. Si este código de estado no es cero (0) es porque hubo errores. Entonces básicamente esa ultima linea es la que ejecuta un bucle que mantiene el programa en ejecución controlada (por decir así) hasta que se envía la orden de cerrarlo (donde recopila información de errores). Si borraras esa ultima linea tu programa se ejecutaría y se cerraría inmediatamente!
app = QtWidgets.QApplication(sys.argv)
Aquí esta instanciando app pasando como argumento de QtWidgets.QApplication a sys.argv. Si nos fijamos en la documentación de Python «sys.argv» retorna una lista de todos los argumentos que se han pasado por lineas de comando. Es decir que, sys.argv retornara una matriz de todos los argumentos que han sido pasados en nuestro código partiendo de cero [0].
MainWindow = QtWidgets.QMainWindow()
Esta instanciando, indica que el objeto MainWindow (nuestra ventana) pertenece a la clase QMainWindow() de la librería QtWidgets. (Aquí en la documentación oficial de PyQt puedes ver mas sobre ella). Entonces al instanciarla esta definiendo todas las propiedades de nuestra ventana. Pero aquellas por defecto, es decir aun no estaríamos aplicando los cambios que realizamos!
ui = Ui_MainWindow()
Aquí indica que ui (objeto) pertenece a la clase UI_MainWindow() que es la que se crea al comienzo de nuestro código luego de la importación de las librerías (Linea 11). Y finalmente llama el método SetupUi:
ui.setupUi(MainWindow)
Entonces aquí es donde se aplica la configuración a nuestra ventana (MainWindow) que tenia por defecto asignado los «estilos por defecto» de QMainWindow()
De esta forma instancia MainWindow con la clase por defecto primeramente, luego crea «ui» instanciadoló a la clase UI_MainWindow que es aquella que tiene nuestras modificaciones y finalmente llama el método setupUI que las aplica a MainWindow. Obtenemos una ventana «por defecto» con nuestras modificaciones (las que aplicamos en Designer) aplicadas a ella. Mas abajo dejo un diagrama.
MainWindow.show()
Este método es el encargado de mostrar la ventana.
Espero haberlo explicado lo mejor posible y si por ahí encuentras algún error déjame un comentario!. En realidad no es muy difícil de entender lo que se hace en este código. Pero tampoco vamos a editar este código para crear nuestra aplicación, en realidad deberemos separar la programacion gráfica de la funcional. Eso lo veremos en la siguiente entrada, pero es importante ir comprendiendo como funciona pyqt.
hola, al instalar pyqt5 en windows, pero al ejecutar me da un error «ImportError: No module named ‘PyQt5.QtWebEngineWidgets’».
Este error se debe a que no se encuentra instalado el modulo QtWebEngine, ya que la instalación por defecto no lo incluye, para solucionar el problema procedemos a instalarlo con el siguiente comando:
pip3 install PyQtWebEngine
así lo hice y parece que me funciona. esta solución la encontre por internet.
aprovecho para felicitarte por el blog , en mi caso me esta siendo muy útil. Tengo que decir que soy un programador senior (tanto que ya estoy jubilado), pero como es un mundo que me gusta, y para hacer algún programilla necesitaba un código de programación abierto, me decante por python y encontré este blog, y hasta el momento muy satisfecho, tanto con las explicaciones y el intentar hacerlo ameno. Gr
gracias de nuevo.
Hola francisco gracias a ti por compartir la solución. Saludos!
Hola! Te felicito por este blog.
Me ha encantado la explicación que haces, pero hay unos detalles que no entiendo. ¿qué significan (A) , (H), y (M) que aparecen en los comentarios del código? He pensado que podían designar atributos, métodos heredados y métodos, respectivamente, pero no lo veo claro.
¿puedes orientarme sobre este detalle?
Saludos y muchas gracias.