Módulo 13

Módulo 13: Exportación y Uso del Archivo .ui

Cómo tu diseño se convierte en una aplicación real

Cómo tu diseño se convierte en una aplicación real

---

Objetivos de Aprendizaje

Al finalizar este módulo serás capaz de:

  • Comprender la estructura de un archivo .ui
  • Cargar archivos .ui directamente con QUiLoader
  • Convertir archivos .ui a código Python con pyside6-uic
  • Entender el flujo de trabajo diseñador → programador
  • Organizar archivos .ui en un proyecto
  • Usar la herramienta de línea de comandos de Custom Widgets
  • Empaquetar recursos junto con archivos .ui

---

13.1 El Archivo .ui

Cuando guardas tu diseño en Qt Designer, se crea un archivo con extensión .ui. Este archivo es XML (texto estructurado) que describe cada widget, su posición, propiedades y conexiones.

🎨 ANALOGÍA DEL DISEÑO

>

El archivo .ui es como tu archivo .psd o .fig: contiene todo tu diseño editable. La diferencia es que en lugar de ser un formato propietario cerrado, es XML abierto que cualquier programa puede leer.

Estructura básica de un archivo .ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Mi Diálogo</string>
  </property>
  <property name="styleSheet">
   <string notr="true">background-color: #1a1a2e;</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QLabel" name="titulo_label">
     <property name="font">
      <font>
       <pointsize>20</pointsize>
       <bold>true</bold>
      </font>
     </property>
     <property name="styleSheet">
      <string notr="true">color: #ffffff;</string>
     </property>
     <property name="text">
      <string>¡Hola Mundo!</string>
     </property>
     <property name="alignment">
      <set>Qt::AlignCenter</set>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QPushButton" name="cerrar_btn">
     <property name="text">
      <string>Cerrar</string>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>cerrar_btn</sender>
   <signal>clicked()</signal>
   <receiver>Dialog</receiver>
   <slot>close()</slot>
  </connection>
 </connections>
</ui>

Partes del archivo .ui

Sección Descripción
--------- -------------
`` Versión del formato .ui
`` Nombre de la clase que se generará
`` El widget principal y sus propiedades
`` Los layouts aplicados
`` Cada widget hijo con sus propiedades
`` Referencias a archivos de recursos (.qrc)
`` Las conexiones de Signals y Slots

---

13.2 Método 1: Cargar directamente con QUiLoader

Este método carga el .ui directamente sin convertirlo. Es como abrir un PSD en Photoshop.

Código para cargar un .ui

from PySide6.QtWidgets import QApplication
from PySide6.QtUiTools import QUiLoader
from PySide6.QtCore import QFile
import sys

def main():
    app = QApplication(sys.argv)

    # Cargar el archivo .ui
    loader = QUiLoader()
    ui_file = QFile("mi_diseno.ui")

    if not ui_file.open(QFile.ReadOnly):
        print("Error: No se pudo abrir el archivo .ui")
        sys.exit(1)

    ventana = loader.load(ui_file)
    ui_file.close()

    if ventana is None:
        print("Error: No se pudo cargar la interfaz")
        sys.exit(1)

    # Mostrar la ventana
    ventana.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()

Ventajas del Método 1

Ventaja Descripción
--------- -------------
**Sin conversión** El .ui se carga directamente
**Cambios instantáneos** Modifica el .ui y los cambios se reflejan al reiniciar
**Ideal para diseñadores** No necesitas tocar Python para actualizar el diseño
**Archivo más pequeño** No se genera código Python adicional

Desventajas

Desventaja Descripción
------------ -------------
**Acceso a widgets** Necesitas usar `ventana.findChild()` para acceder a widgets específicos
**Rendimiento** Ligeramente más lento que el método 2 (imperceptible en la práctica)
**Sin autocompletado** El IDE no conoce los widgets del .ui

Cómo acceder a widgets específicos

# Acceder a un widget por nombre
titulo = ventana.findChild(QLabel, "titulo_label")
titulo.setText("Nuevo texto")

# Acceder a un botón y conectar una señal
boton = ventana.findChild(QPushButton, "guardar_btn")
boton.clicked.connect(lambda: print("¡Guardado!"))

---

13.3 Método 2: Convertir a Python con pyside6-uic

Este método convierte el .ui a código Python. Es como "exportar" tu diseño a código.

Paso 1: Convertir el archivo

pyside6-uic mi_diseno.ui -o ui_mi_diseno.py

Paso 2: Usar el archivo generado

from PySide6.QtWidgets import QApplication, QDialog
from ui_mi_diseno import Ui_Dialog
import sys

class MiVentana(QDialog):
    def __init__(self):
        super().__init__()
        # Crear la interfaz desde el archivo convertido
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)

        # Ahora puedes acceder a los widgets directamente
        # self.ui.titulo_label.setText("Nuevo texto")
        # self.ui.cerrar_btn.clicked.connect(self.close)

def main():
    app = QApplication(sys.argv)
    ventana = MiVentana()
    ventana.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()

Ventajas del Método 2

Ventaja Descripción
--------- -------------
**Acceso directo** `self.ui.titulo_label` en lugar de `findChild()`
**Autocompletado** El IDE conoce todos los widgets
**Rendimiento** Ligeramente más rápido
**Integración con código** Fácil de extender con lógica personalizada

Desventajas

Desventaja Descripción
------------ -------------
**Requiere conversión** Debes convertir cada vez que cambias el .ui
**Archivo adicional** Se genera un archivo .py extra
**No editar el .py** Nunca edites el archivo generado manualmente

---

13.4 Método 3: Usar Custom Widgets CLI

La biblioteca QT-PyQt-PySide-Custom-Widgets incluye herramientas de línea de comandos.

Convertir .ui a Python

Custom_Widgets --convert-ui mi_diseno.ui --qt-library PySide6

Monitorear cambios (hot reload)

Custom_Widgets --monitor-ui mi_diseno.ui --qt-library PySide6

Esto convierte automáticamente el .ui a Python cada vez que guardas cambios en Qt Designer.

Lanzar Qt Designer con plugins custom

Custom_Widgets --start-designer --plugins

---

13.5 Flujo de Trabajo Diseñador → Programador

En un equipo real, el flujo de trabajo ideal es:

┌─────────────────────────────────────────────────────────────┐
│                     FLUJO DE TRABAJO                        │
│                                                             │
│  ┌─────────────┐         ┌─────────────┐                    │
│  │  DISEÑADOR  │         │ PROGRAMADOR │                    │
│  │             │         │             │                    │
│  │  Qt Designer│         │  Python +   │                    │
│  │       │     │         │  PySide6    │                    │
│  │       ▼     │         │       ▲     │                    │
│  │  Archivo .ui│ ──────► │  Carga .ui │                    │
│  │             │         │       │     │                    │
│  │  Modifica   │ ──────► │  Se     │                    │
│  │  el .ui     │         │  actualiza│                    │
│  │             │         │       │     │                    │
│  │             │ ◄────── │  Prueba │                    │
│  │             │         │  y reporta│                    │
│  └─────────────┘         └─────────────┘                    │
└─────────────────────────────────────────────────────────────┘

Roles claros

Rol Responsabilidades Herramientas
----- ------------------- --------------
**Diseñador** Crear la interfaz visual, definir layouts, aplicar estilos, configurar signals/slots básicos Qt Designer
**Programador** Cargar el .ui, agregar lógica, conectar con bases de datos, manejar eventos complejos Python + PySide6

🎨 ANALOGÍA DEL DISEÑO

>

Es como trabajar con un desarrollador web: tú diseñas en Figma, el programador convierte a HTML/CSS. La diferencia es que con Qt Designer, el archivo .ui YA es el "código" de la interfaz. No hay conversión manual necesaria.

---

13.6 Organización de Archivos en un Proyecto

Estructura recomendada

mi_proyecto/
├── main.py                    # Punto de entrada de la aplicación
├── requirements.txt           # Dependencias (PySide6, etc.)
│
├── ui/                        # Archivos .ui de Qt Designer
│   ├── main_window.ui
│   ├── dialog_config.ui
│   ├── dialog_registro.ui
│   └── components/
│       ├── sidebar.ui
│       └── tarjeta_producto.ui
│
├── src/                       # Código Python generado (opcional)
│   ├── __init__.py
│   ├── ui_main_window.py
│   └── ui_dialog_config.py
│
├── resources/                 # Recursos visuales
│   ├── recursos.qrc
│   ├── iconos/
│   │   ├── guardar.svg
│   │   └── eliminar.svg
│   └── imagenes/
│       └── logo.png
│
├── styles/                    # Hojas de estilo
│   └── tema_oscuro.qss
│
└── json_styles/               # Temas JSON (Custom Widgets)
    └── style.json

💡 CONSEJO: Mantén todos los archivos .ui en una carpeta ui/ separada del código Python. Esto hace que sea fácil para el diseñador encontrar sus archivos sin tocar el código.

---

13.7 Empaquetar la Aplicación

Cuando estés listo para distribuir tu aplicación:

Con PyInstaller

# Instalar PyInstaller
pip install pyinstaller

# Crear el ejecutable
pyinstaller --onefile --windowed --add-data "ui;ui" --add-data "resources;resources" main.py

Con cx_Freeze

# setup.py
from cx_Freeze import setup, Executable

setup(
    name="Mi Aplicacion",
    version="1.0",
    description="Mi aplicacion de escritorio",
    executables=[Executable("main.py", base="Win32GUI")],
    include_files=[("ui/", "ui/"), ("resources/", "resources/")],
)

---

13.8 Errores Comunes al Exportar

Error Causa Solución
------- ------- ----------
**"No se pudo abrir el archivo .ui"** La ruta del archivo es incorrecta Usa rutas relativas o absolutas correctas
**"No se encontró el widget"** El nombre del widget no coincide Verifica el `objectName` en Qt Designer
**"Error al cargar recursos"** El archivo .qrc no está incluido Empaqueta los recursos con la aplicación
**Los estilos no se aplican** El styleSheet no se cargó correctamente Verifica que el styleSheet esté en el .ui o cárgalo desde código
**Las conexiones no funcionan** Los signals/slots no se configuraron bien Verifica las conexiones en el .ui o conéctalas en código

---

Ejercicio Práctico del Módulo

🏋️ EJERCICIO 13: Cargar tu Diseño en Python

>

Objetivo: Tomar un archivo .ui creado previamente y cargarlo con Python.

>

Pasos:

1. Toma cualquier archivo .ui que hayas creado en ejercicios anteriores

2. Crea un archivo main.py en la misma carpeta

3. Escribe el código para cargar el .ui con QUiLoader (Método 1)

4. Ejecuta python main.py y verifica que la ventana se abre correctamente

5. Ahora convierte el .ui con pyside6-uic tu_archivo.ui -o ui_tu_archivo.py

6. Modifica main.py para usar el archivo convertido (Método 2)

7. Ejecuta nuevamente y verifica que funciona igual

8. Agrega una línea de código que cambie el texto de un Label al iniciar

9. Agrega una conexión de señal en Python para un botón

10. Experimenta con ambos métodos y decide cuál prefieres

>

Resultado esperado: Dos versiones funcionales de la misma interfaz, una cargando el .ui directamente y otra usando el archivo convertido.

---

Recursos Adicionales

Recurso Descripción
--------- -------------
[QUiLoader Documentation](https://doc.qt.io/qt-6/quiloader.html) Documentación de QUiLoader
[pyside6-uic Documentation](https://doc.qt.io/qtforpython-6/overviews/uifiles.html) Documentación de pyside6-uic
[PyInstaller Documentation](https://pyinstaller.org) Documentación de PyInstaller
[Custom Widgets CLI](https://qtcustomwidgets.spinncode.com/API-Reference/CMD) Herramientas de línea de comandos

---

Evaluación de Comprensión

  1. ¿Qué formato tiene un archivo .ui?
  2. ¿Cuál es la ventaja principal del Método 1 (QUiLoader)?
  3. ¿Cuál es la ventaja principal del Método 2 (pyside6-uic)?
  4. ¿Qué comando convierte un .ui a Python?
  5. ¿Por qué NO debes editar manualmente el archivo .py generado?
  6. ¿Cómo accedes a un widget específico cuando usas QUiLoader?
  7. ¿Qué hace el comando Custom_Widgets --monitor-ui?
  8. ¿Cuál es la estructura de carpetas recomendada para un proyecto?
  9. ¿Cómo empaquetas una aplicación con PyInstaller incluyendo los archivos .ui?
  10. ¿Qué rol tiene el diseñador y qué rol tiene el programador en el flujo de trabajo?

---

Módulo anterior: ← [Módulo 12: Widgets Especializados](11-widgets-especializados.md)

Siguiente módulo: → [Módulo 14: Mejores Prácticas](13-mejores-practicas.md)

📝 Evaluación de Comprensión

Escribe tus respuestas y luego presiona el botón para comparar con las respuestas correctas.

1. ¿Qué formato tiene un archivo .ui?
✅ Respuesta Correcta
XML (texto estructurado) que describe cada widget, su posición, propiedades y conexiones.
2. ¿Cuál es la ventaja principal del Método 1 (QUiLoader)?
✅ Respuesta Correcta
Sin conversión: el .ui se carga directamente, los cambios se reflejan al reiniciar sin necesidad de regenerar código, ideal para diseñadores que no tocan Python.
3. ¿Cuál es la ventaja principal del Método 2 (pyside6-uic)?
✅ Respuesta Correcta
Acceso directo a los widgets (self.ui.nombre_widget), autocompletado del IDE, ligeramente más rápido y fácil de extender con lógica personalizada.
4. ¿Qué comando convierte un .ui a Python?
✅ Respuesta Correcta
pyside6-uic archivo.ui -o ui_archivo.py
5. ¿Por qué NO debes editar manualmente el archivo .py generado?
✅ Respuesta Correcta
Porque se regenera cada vez que conviertes el .ui, por lo que cualquier edición manual se perdería. La lógica personalizada debe ir en una clase separada que herede de la UI generada.
6. ¿Cómo accedes a un widget específico cuando usas QUiLoader?
✅ Respuesta Correcta
Usando ventana.findChild(TipoWidget, 'nombre_del_widget'), por ejemplo: ventana.findChild(QLabel, 'titulo_label').
7. ¿Qué hace el comando Custom_Widgets --monitor-ui?
✅ Respuesta Correcta
Monitorea cambios en el archivo .ui y lo convierte automáticamente a Python cada vez que guardas cambios en Qt Designer (hot reload).
8. ¿Cuál es la estructura de carpetas recomendada para un proyecto?
✅ Respuesta Correcta
ui/ (archivos .ui), src/ (código Python generado), resources/ (recursos visuales), styles/ (hojas de estilo), main.py (punto de entrada).
9. ¿Cómo empaquetas una aplicación con PyInstaller incluyendo los archivos .ui?
✅ Respuesta Correcta
pyinstaller --onefile --windowed --add-data 'ui;ui' --add-data 'resources;resources' main.py
10. ¿Qué rol tiene el diseñador y qué rol tiene el programador en el flujo de trabajo?
✅ Respuesta Correcta
El diseñador crea la interfaz visual, define layouts, aplica estilos y configura signals/slots básicos usando Qt Designer. El programador carga el .ui, agrega lógica, conecta con bases de datos y maneja eventos complejos usando Python + PySide6.