Separar el código de la interfaz gráfica – (Inicia tu proyecto) PyQt5

Hey lectores hoy como prometí vamos a ver como separar el código python de la interfaz gráfica!

Como había dicho antes, cuando hablamos de los módulos y librerías en python es muy importante tener en cuenta que nuestro programa no «debería» estar compuesto por miles de funciones, gráfica, complementos todo en el mismo archivo. No solo porque no es una buena practica de programacion; sino porque se nos van a complicar las cosas a la hora de querer modificarlo u actualizarlo.

Podemos separar el código perfectamente de nuestras aplicaciones o programas no solo de la forma que se recomienda, sino también de la que nos quede mas cómoda a nosotros y a nuestro usuario. De esta manera ademas de estar mas organizado mejoramos mucho la ejecución, lectura e interpretación del código, entre otras ventajas que seguro iras viendo por ti mismo.

Bien ahora si, a lo que íbamos.

¿Porque separar el código de la interfaz gráfica?

El problema:

En la lección anterior vimos como crear una ventana con QtDesigner, la exportamos en un archivo .ui el cual finalmente convertimos a un archivo de Python. Hasta ahí todo bien!

El verdadero problema existe cuando tu comienzas a añadir código funcional a ese archivo (que fue convertido) llamemosle en el ejemplo: miventana_ui.py

Si tu añadiste código funcional a ese archivo py y luego quieres editar el diseño usando Qtdesigner. Estarás en un problema ya que deberás generar un nuevo archivo .ui. Y habrás perdido los cambios que hallas realizado en cuanto a código funcional. Porque tendrás un nuevo archivo. Me explico?

Al crear un nuevo archivo .ui, debemos volver a convertirlo a (.py) y allí no se encontrara nuestro código funcional (el que brinda las acciones del programa). Deberemos volver a copiarlo, modificarlo y así sucesivamente perdiéndonos en un laberinto de archivos de residuo y modificaciones interminables. Porque ambos sabemos que no vas a diseñar la interfaz una sola vez y así va a quedar.

 

La solución; dividir el código:

 

Separar el código

Así deberíamos organizar nuestros archivos; de esta manera tendremos nuestro código funcional en Mi programa. Y la interfaz gráfica en otro archivo (_ui.py) que podremos reemplazar tranquilamente luego de modificarlo con QtDesigner!

Cuando comiences un nuevo proyecto de una aplicación entonces puedes definirte por una de estas dos maneras de organizar tu código. Yo te recomiendo la manera 2, por ser mas practica.

 


≥ Manera 1 de dividir tu proyecto

Así que vamos a ver como haríamos esto basándonos en el código de la ventana que creamos en Pyqt5.

 

Carpeta miprograma

Vamos a crear un nuevo archivo de Python usando nuestro IDE, en mi caso geany y vamos a guardarlo junto a nuestro archivo «miventana_ui.py». Llamare a este archivo Miprograma.py y colocare todo dentro de una carpeta incluido el archivo «miventana.ui»

 

Lo que vamos a hacer es utilizar miventana_ui.py desde Miprograma.py

Por empezar en Miprograma.py debemos importar todo lo que esta declarado en miventana_ui.py así:

Importar archivo ui en python Estamos importando el código del archivo «.py», no el «.ui» que quede claro. Fíjate bien en los nombres de archivos.

Utilizamos from «modulo» import * (todo explícito)

 

 

 Creamos la clase VentanaPrincipal heredando de Qtwidgets.QMainWindow

 

Qwidgets y las librerías de Pyqt ya están importadas dentro de «miventana_ui.py» por lo que podremos utilizarlas sin necesidad de volver a importar en Miprograma.py. Así que vamos a crear la clase VentanaPrincipal que nos permitirá cargar la ventana principal de nuestro programa:

 

Hasta aquí hemos importado la ventana principal mediante Qtwidgets.QMainWindow utilizando una clase llamada VentanaPrincipal. Colocaremos dentro de ella un simple «pass». Para que pase de ella, esa clase aun no contiene nada.

Prueba a ejecutar el archivo desde la consola para corroborar que no tienes errores al importar, si obtienes un error NameError es probable que te hallas equivocado importando el archivo «.py» o en la herencia de Qtwidgets.QMainWindow. De lo contrario no sucedera nada.. Porque..

Creando el bucle de ejecución de nuestro programa

Recuerdas que explicamos un condicional dentro de miventana_ui.py?. Pues ese condicional esta evitando ahora mismo que cuando tu ejecutes Miprograma.py no se abra miventana_ui.py. Y tampoco queremos que sea así!, por lo que este condicional nos permite que miventana_ui.py funcione como un módulo de Miprograma.py. 

En este condicional (que ya no se cumple porque ahora esta como módulo) se encontraba un bucle de ejecución recuerdas?. Pues eso es lo que necesitamos para Miprogramaa.py!

Este es el condicional del que te hablaba:

Excepto que vamos a copiarlo y pegarlo en Miprograma.py, pero vamos a modificarlo instanciando nuestra clase VentanaPrincipal a nuestro objeto «ventana» que sera el que determine el comportamiento de la ventana principal.

Así que este condicional queda así:

 

Código de Miprograma.py:

 

Como resultado de ejecución obtenemos lo siguiente:

Separar el código de pyqt5

 

 

-Pero eso es una ventana cutre, vacía, sin sentido en la vida!

-Si porque solo importamos solo la ventana principal, ahora vamos a traer nuestro diseño a ella!!

Para eso debemos heredar la clase UI_MainWindow que es la que contiene las propiedades de nuestro diseño (el que realizamos en QtDesigner). Dicha clase se modifica cada vez que cambiamos nuestro diseño. Haaaa.. Ahora entiendes!. Cuando cambiemos el diseño se importara la clase con el nuevo código y obtendremos el nuevo diseño!!

A ello! que no tengo todo el día!

 

Importando nuestro diseño, clase UI_MainWindow

Esta clase se encuentra en miventana_ui.py y vamos a colocarla como herencia dentro de nuestra clase VentanaPrincipal que hemos creado al principio! Quedando así:

Ahora debemos llamar al método constructor de la ventana dentro de esta clase MainWindow, recuerdas cual era?

SetupUI!

Pero como sabrás primero debemos crear el constructor de la clase. Usando __init__

Así que en nuestra clase VentanaPrincipal debemos crear un constructor y llamar el método setupUI indicando como parámetro self (a si mismo (objeto)).

Aquí estamos creando el constructor de la clase VentanaPrincipal y llamando al método setupUi con el parámetro self. Pero obtendremos un error grande como una casa:

Traceback (most recent call last):
File «Miprograma.py», line 13, in <module>
ventana = VentanaPrincipal()
File «Miprograma.py», line 8, in __init__
self.setupUi(self)
File «/home/pyro/Escritorio/Miprograma/miventana_ui.py», line 15, in setupUi
MainWindow.setObjectName(«MainWindow») #Define el nombre de la ventana (objeto) mediante método (H)
RuntimeError: super-class __init__() of type VentanaPrincipal was never called

¿Porque?

Traducción del error usando el traductor de google:

RuntimeError: la superclase __init __ () del tipo VentanaPrincipal nunca fue llamada

Porque al crear la clase VentanaPrincipal estamos usando herencia  y no llamamos al constructor de las clases padres entonces el interprete no encuentra el método setupUI. Sabe que hereda porque lo hemos especificado, pero no encuentra el método!!

Venga te lo esta diciendo, el interprete nos pide Super()

 

Aplicando super() en pyqt

Así que aplicando un simple super accedemos al bendito método; quedando nuestro código así:

Atencion!

Pero eso si, si respetas el orden de la herencia múltiple de las clases: (QtWidgets.QMainWindow, Ui_MainWindow). Pues el método setupUI esta en la clase Ui_MainWindow y  alli es donde buscara python siguiendo el MRO. Que explicamos en super(). Caso contrario, deberíamos especificar el nombre de la clase llamando su constructor «Ui_MainWindow.__init__». Si todo esto no te resulta familiar lee aquí sobre la función super() y el MRO.

 

Resultado de la ejecución de Miprograma.py:

Ventana principal + diseño propio Designer Pyqt5

 

Añadido!

Guaala!! Logramos separar el código del diseño!. Así como así!

Haber.. mmm.. si te quedan dudas vamos a agregar otro botón y cambiar esos textos feos en QtDesigner!

 

El resultado esperado! Pyqt5 separado el código del diseño

 

Vamos nuevamente a QtDesigner! y abrimos nuestro archivo «.ui» nuevamente!

Carpeta con archivos de python Recuerda siempre tener todos los archivos en una carpeta de tu programa para evitar el desorden de archivos.

En QtDesigner vas a abrir..>y alli buscas tu archivo.ui

Editas lo que sea necesario, en mi caso solo hago algunas modificaciones para que sea notable que se encuentra separada la lógica del diseño de nuestro programa como ves mas abajo.

 

QtDesigner cambiar texto label

 

Aquí como estas viendo estoy jugando con los tamaños de letra de la fuente del label. Quedando mi ventanita así:

Mi primera ventana en pyqt5 con el código separado
Ahora vamos otra vez a repetir el proceso que hicimos antes de exportarlo como «.ui» y luego pasarlo a «.py». Pero en mi caso solo voy a reemplazar los archivos, porque me tengo fe!. Porque quiero y porque puedo!

Vamos a guardar como…> La carpeta de nuestro programa ..> reemplazamos el archivo miventana.ui

Ahora vamos a borrar miventana_ui.py y lo volveremos a crear con el mismo nombre, para no tener que modificar el código de mi programa e importar nuevamente miventana_ui.py como modulo. Vamos a la consola y procedemos a convertir el ui nuevamente a py.

«Venga que python es fácil, cualquier programador de html puede aprenderlo :OOOOOO» <- Es broma,  no vengamos aquí a montar un debate.

Bien, ahora una vez convertida nuestra ventana_ui.py ha cambiado, se ha reemplazado. Y como tenemos las cosas separadas al ejecutar Miprograma.py debería verse la modificación!

  • Ya ejecuta esa mierda de una vez!!

Pythones es python perras

 

 


≥ Manera 2 de organizar tu proyecto

Esta segunda manera seguro te resultara mas fácil y mas organizada, si solo vas a trabajar con Designer en este caso voy a aplicarla a Miprograma.py nuevamente. De esta forma no necesitas convertir el archivo .ui a .py sino que lo llamas directamente haciendo uso del módulo uic.

Fijare en el siguiente código (recuerda que en este caso utilizo la misma clase que en la manera 1 «VentanaPrincipal» )

Y el resultado:

 

Bueno se vera un poco diferente en estética pero es porque yo he cambiado de SO y PC. Pero en fin, funciona bien!
Y en este caso nuestra carpeta de proyecto solo necesitara los dos archivos, el Py con nuestro código funcional y el archivo .ui con la interfaz gráfica.

 

 


 

Y así me despido, cambiaría un poco el código de Miprograma.py para que al presionar «OK» se cerrase la ventana, pero se me hace muy larga la entrada y mi pc con 1gb de ram esta que pela fuego, así que en la siguiente nos vemos!. Y también quería contarles que mañana llega mi hermano con una super PC gamer para mi y prometo partir el blog a posteos! Así que si no lo han echo, es momento de suscribirse perras!

 

 

Ayúdame a llegar a mas personas!
  • 6
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  • 6
  •  
  •  
  •  
  •  
  •  
  •