Técnico Universitario en Programación Guía de exploración · para hacer con la compu abierta

Explorar PyQt

Esta guía no te enseña PyQt. Te enseña a empezar a usarlo, a experimentar y a averiguar lo que todavía no sabés. Vas a escribir código antes de entenderlo del todo — y está bien: así se aprende una librería nueva.

PyQt6 pip install Widgets Eventos Layouts PyQt + POO Investigación
o usá Cmd + P (Mac) · Ctrl + P (Windows) → Guardar como PDF
Cómo se trabaja esta guía
  1. Observá el ejemplo. No hace falta entender cada línea antes de ejecutarlo.
  2. Probalo tal cual está. Que funcione primero.
  3. Modificalo. Cambiá valores, rompelo a propósito, mirá qué pasa.
  4. Investigá lo que la guía no te dice. Es parte de la actividad, no una falla tuya.
  5. Resolvé el desafío con lo que averiguaste.
  6. Creá algo propio al final.
La idea central de toda la guía

Un programador no memoriza una librería.
Aprende a investigarla y utilizarla.

El recorrido
  1. 01Antes de empezar
  2. 02Instalación
  3. 03Primer experimento: la ventana
  4. 04Conociendo los widgets
  5. 05El primer evento
  6. 06Experimento: formulario
  7. 07Layouts
  8. 08PyQt + POO
  9. 09Desafío guiado: «Mi primera aplicación»
  10. 10Misión de investigación 🔎
  11. 11Mini proyecto (elegís vos)
  12. 12Desafíos «¿Y si...?»
  13. 13Relación con Arena de Combate
  14. 14Desafío final
  15. 15Checklist
01

Antes de empezar

Qué es PyQt y por qué existen varias herramientas gráficas

Qué es

PyQt es una librería que nos permite crear aplicaciones de escritorio con interfaz gráfica desde Python: ventanas, botones, formularios, tablas, menús. Por dentro usa Qt, un framework escrito en C++ con el que están hechos programas que seguramente usaste. PyQt es el puente que nos deja manejarlo desde Python.

Sirve para

Aplicaciones con ventanas: un gestor, un panel de control, un reproductor, una herramienta interna, un formulario de carga.

Se ve

Como un programa del sistema operativo. No parece un ejercicio de cátedra: parece software.

No sirve para

Un videojuego con movimiento fluido, física y sprites. Para eso ya conocemos Pygame.

Cuatro herramientas, cuatro necesidades

HerramientaQué construyeCuándo la elegís
Consolatexto que entra y saleCuando lo importante es la lógica y nadie más va a usarlo.
Tkinterventanas simplesViene con Python, no se instala nada. Ideal para algo chico y rápido.
PyQtaplicaciones de escritorioCuando querés algo más completo, prolijo y que crezca.
PygamevideojuegosCuando hay movimiento, colisiones, sonido y un bucle de juego.
Lo importante

No hay una herramienta «mejor». Hay herramientas distintas para necesidades distintas. Parte de programar es elegir con cuál resolver el problema que tenés enfrente.

02

Instalación

PyQt no viene con Python: hay que traerlo

pip install PyQt6
En la terminal, no dentro de Python. Si pip no funciona, probá pip3 install PyQt6 o python -m pip install PyQt6.
Instalar

Descarga el código de la librería y lo guarda en tu Python, una sola vez por computadora (o por entorno virtual).

Importar

Trae ese código a este programa, cada vez que lo ejecutás. Sin instalar, el import falla.

Probá · que la instalación funcionó

Creá un archivo, escribí esta única línea y ejecutalo. Si no aparece ningún error, ya está:

import PyQt6
print("PyQt6 instalado")
Ojo · PyQt5 vs PyQt6

Existen las dos versiones y en internet vas a encontrar ejemplos de ambas. Esta guía usa PyQt6 de principio a fin. Si copiás un ejemplo que dice PyQt5 y no anda, no está roto: está escrito para otra versión. En la sección 10 vas a encontrar cómo traducirlo.

Para pensar
  • ¿Qué otras librerías instalaron con pip hasta ahora? ¿Cuáles no hizo falta instalar?
  • Si borrás la carpeta del proyecto, ¿PyQt6 se desinstala? ¿Por qué?
03

Primer experimento: la ventana

Escribilo, ejecutalo, y recién después entendelo

Este es el programa PyQt más chico que hace algo visible. Copialo en un archivo ventana.py y ejecutalo.

import sys
from PyQt6.QtWidgets import QApplication, QWidget

app = QApplication(sys.argv)

ventana = QWidget()
ventana.setWindowTitle("Mi primera aplicación")
ventana.resize(500, 300)

ventana.show()

sys.exit(app.exec())
Nueve líneas. Tenés una ventana de verdad, con su barra de título, su botón de cerrar y se puede redimensionar. Todo eso ya estaba hecho: nosotros solo lo pedimos.

Lo mínimo para entenderlo

QApplicationLa aplicación en sí. Es quien se queda escuchando lo que hace el usuario. Se crea una sola por programa y va siempre primero.
QWidgetUn elemento de interfaz. Si no está adentro de nada, aparece como ventana. Todo lo que veas en PyQt es, en el fondo, un widget.
show()Pide que se muestre. Crear un widget no lo hace visible.
exec()Arranca el bucle de eventos: el programa se queda vivo esperando clics y teclas hasta que cerrás la ventana.
Respondé antes de seguir (probando, no adivinando)
  • ¿Qué hace QApplication? ¿Por qué creés que necesita sys.argv?
  • ¿Qué representa QWidget?
  • ¿Qué hace resize()? ¿Y qué pasa si después agrandás la ventana con el mouse?
  • ¿Qué hace show()?
  • ¿Qué pasaría si eliminamos show()? ¿El programa da error, o hace otra cosa?
Probá · rompelo a propósito
  • Borrá la línea ventana.show() y ejecutá. ¿Qué ves? ¿El programa terminó?
  • Borrá la última línea (sys.exit(app.exec())). ¿Cuánto dura la ventana?
  • Cambiá resize(500, 300) por resize(200, 800). ¿Qué número es cuál?
  • Poné tu nombre en el título.
¿Y si...?

¿Y si creás dos ventanas en el mismo programa? Probá: creá ventana2, dale otro título y llamá a show() en las dos. ¿Funciona? ¿Y si al cerrar una se cierra la otra?

04

Conociendo los widgets

Las piezas con las que se arma una interfaz

Widget

Cada pieza visible de la interfaz es un widget: una etiqueta, un botón, un campo de texto. Todos son objetos — los creás, guardás en una variable y les pedís cosas con métodos. Esto ya lo sabés hacer: es exactamente lo mismo que hiciste con Personaje o Arma.

El banco de pruebas

Guardá este archivo como banco.py. Cada widget que quieras probar lo pegás en el medio, entre las líneas de guiones.

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel

app = QApplication(sys.argv)
ventana = QWidget()
ventana.setWindowTitle("Banco de pruebas")
ventana.resize(420, 320)

# ---------- pegá acá los widgets que pruebes ----------
etiqueta = QLabel("Hola mundo", ventana)
etiqueta.move(20, 20)
# ------------------------------------------------------

ventana.show()
sys.exit(app.exec())
Dos cosas nuevas: el segundo argumento (ventana) dice adentro de qué vive el widget, y move(x, y) lo ubica a mano en esa posición. Acordate de move(): en la sección 7 vamos a querer sacárnoslo de encima.
Error clásico

Si creás un widget y te olvidás el , ventana, no aparece nada — o se abre en una ventana suelta. No es un bug: el widget no sabe dónde vivir. Y todo widget que uses hay que importarlo arriba, en la línea del from PyQt6.QtWidgets import ....

Seis widgets para empezar

QLabel · mostrar texto

Muestra un texto (o una imagen) que el usuario lee pero no edita. Es la salida de tu app.

etiqueta = QLabel("Hola mundo", ventana)

Modificá: ¿cómo le cambiarías el texto después de haberlo creado?

Pista: casi todos los widgets tienen métodos que empiezan con set. Probá escribir etiqueta.set y mirá qué te sugiere el editor.

Investigá: ¿cómo se centra el texto de un QLabel?

QPushButton · el botón

Lo que el usuario aprieta. Por ahora no hace nada al hacer clic: eso llega en la sección 5.

boton = QPushButton("Saludar", ventana)
boton.move(20, 60)

Modificá: poné tres botones con textos distintos, uno debajo del otro.

Investigá: ¿cómo se le cambia el tamaño a un botón?

QLineEdit · escribir una línea

Un campo de texto de una sola línea: un nombre, una edad, una búsqueda. Es la entrada de tu app.

from PyQt6.QtWidgets import QLineEdit

campo = QLineEdit(ventana)
campo.move(20, 100)

Modificá: hacé que arranque con un texto ya escrito adentro.

Investigá: ¿cómo se lee lo que el usuario escribió? ¿Y cómo se muestra un texto gris de ayuda que desaparece al escribir (placeholder)?

QTextEdit · escribir varias líneas

Como el anterior, pero para textos largos: una descripción, notas, un registro de lo que pasó.

notas = QTextEdit(ventana)
notas.move(20, 140)

Modificá: agrandalo con resize() y escribí varias líneas adentro.

Investigá: para leer su contenido no sirve text(). ¿Cuál es el método? ¿Y cómo se hace para que sea de solo lectura?

QCheckBox · sí o no

Una opción que se activa o desactiva. Guarda un estado: True o False.

acepta = QCheckBox("Acepto los términos", ventana)
acepta.move(20, 260)

Modificá: hacé que arranque ya tildado.

Investigá: ¿cómo se pregunta desde el código si está tildado o no?

QComboBox · elegir de una lista

Una lista desplegable. Sirve cuando las opciones son fijas y no querés que el usuario escriba mal.

clase = QComboBox(ventana)
clase.addItems(["Guerrero", "Mago", "Arquero"])
clase.move(20, 290)

Modificá: agregale una cuarta opción.

Investigá: ¿cómo se averigua cuál opción eligió el usuario? ¿Y en qué se diferencia de preguntar por el índice de la opción?

Investigá · el patrón que se repite

Mirá los seis widgets juntos. Casi todos los métodos empiezan igual: set...() para cambiar algo, y un método sin set para preguntar algo. setText() / text(). Si entendés ese patrón, no necesitás memorizar la lista de métodos: podés adivinar el nombre y verificarlo en la documentación.

05

El primer evento

El usuario hace algo → nuestro programa responde

El cambio de mentalidad

En consola nosotros decidíamos el orden: primero esto, después aquello, y el programa esperaba con input(). En una interfaz gráfica es al revés: el usuario decide qué toca y cuándo. Nuestro trabajo es dejar preparado qué hacer si pasa cada cosa.

EL USUARIO HACE CLIC
▼evento
SE EJECUTA NUESTRA FUNCIÓN
▼respuesta
LA INTERFAZ CAMBIA

La línea que conecta las dos cosas

boton.clicked.connect(mi_funcion)
clicked es algo que puede ocurrir. connect() dice qué función queremos que se ejecute cuando ocurra.
El error más común de toda la guía

Se escribe connect(saludar), sin paréntesis al final. Con connect(saludar()) Python ejecuta la función ahí mismo y le pasa el resultado a connect. No estamos llamando a la función: estamos entregándola para que PyQt la llame más tarde.

Una app completa que responde

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton

app = QApplication(sys.argv)
ventana = QWidget()
ventana.setWindowTitle("Evento")
ventana.resize(320, 160)

etiqueta = QLabel("Todavía no me saludaste", ventana)
etiqueta.move(30, 40)
etiqueta.resize(250, 24)

boton = QPushButton("Saludar", ventana)
boton.move(30, 90)

def saludar():
    etiqueta.setText("¡Hola!")

boton.clicked.connect(saludar)

ventana.show()
sys.exit(app.exec())
Ejecutalo y hacé clic. Ese es el corazón de toda interfaz gráfica: un evento y una respuesta. Todo lo que viene después son variaciones de esto.
Probá
  • Hacé clic varias veces. ¿Cambia algo después del primer clic? ¿Por qué?
  • Hacé que el botón cuente los clics: «Me apretaste 3 veces». ¿Dónde guardás el número?
  • Agregá un segundo botón que devuelva la etiqueta a su texto original.
  • Conectá los dos botones a la misma función. ¿Se puede?
Para pensar
  • ¿En qué momento se ejecuta saludar? ¿Cuando se escribe la línea del connect, o después?
  • La función saludar usa etiqueta sin recibirla como parámetro. ¿Por qué funciona? ¿Te parece una buena idea a medida que el programa crezca? (Guardá esa duda: la sección 8 la resuelve.)
06

Experimento: formulario

Ahora sí: datos que entran, datos que salen

Hasta acá el botón siempre decía lo mismo. Vamos a hacer que la respuesta dependa de lo que el usuario escribió.

------------------------------
       MI APLICACIÓN
------------------------------

Nombre: [____________]

Edad:   [____________]

        [ SALUDAR ]

Hola Pedro, tenés 20 años.
Esto es lo que tiene que quedar funcionando. El diseño puede ser feo: por ahora importa que ande.

Lo que tenés que averiguar

LeerCómo obtener el texto que el usuario escribió en un QLineEdit. Es un método corto, sin set.
EscribirCómo cambiar el texto de un QLabel. Esto ya lo usaste en la sección 5.
ReaccionarCómo hacer que todo eso ocurra al hacer clic. También lo usaste: .clicked.connect(...).
Investigá · no te damos el código entero

Buscá «PyQt6 QLineEdit get text» o mirá la documentación de QLineEdit. Vas a encontrar la respuesta en menos de un minuto. Eso es parte de la actividad: esta guía no te va a dar todos los métodos, porque el objetivo es que aprendas a encontrarlos.

El esqueleto

def saludar():
    nombre = campo_nombre.???        # ← leer el nombre
    edad = campo_edad.???            # ← leer la edad
    resultado.setText(f"Hola {nombre}, tenés {edad} años.")

boton.clicked.connect(saludar)
Completá los dos ???. El resto ya lo sabés escribir.
Probá · después de que funcione
  • Dejá los campos vacíos y hacé clic. ¿Qué muestra? ¿Está bien que muestre eso?
  • Escribí veinte en la edad. ¿Rompe? ¿Y si además querés calcular edad + 1?
  • ¿De qué tipo es lo que devuelve el campo de edad? Comprobalo con type() antes de suponerlo.
¿Y si...?

¿Y si en vez de saludar, la app calcula el año de nacimiento? ¿Qué línea cambia y qué línea queda igual?

07

Layouts

Ya tenemos varios elementos. ¿Cómo los organizamos?

Agrandá con el mouse la ventana del formulario que acabás de hacer. ¿Qué pasa con los widgets?

El problema de move()

Con move(x, y) vos clavás cada widget en un punto fijo. Si la ventana cambia de tamaño, si el texto es más largo, si lo abrís en otra computadora: queda todo desacomodado. Y cada vez que agregás algo en el medio, tenés que recalcular a mano las coordenadas de todo lo que está abajo.

La solución

Un layout es un organizador: vos le decís en qué orden van los widgets y él calcula las posiciones y las recalcula solo cuando algo cambia. Nunca más coordenadas a mano.

Los tres que necesitás hoy

QVBoxLayout

Uno debajo del otro

A
B
C

La V es de vertical. El más usado.

QHBoxLayout

Uno al lado del otro

A  B  C

La H es de horizontal. Ideal para una fila de botones.

QGridLayout

En filas y columnas

A  B
C  D

Una grilla. Ideal para formularios y calculadoras.

Vertical: el patrón de tres pasos

from PyQt6.QtWidgets import QVBoxLayout

layout = QVBoxLayout()          # 1. creo el organizador
layout.addWidget(etiqueta)       # 2. le agrego los widgets, en orden
layout.addWidget(campo)
layout.addWidget(boton)
ventana.setLayout(layout)        # 3. se lo pongo a la ventana
Con el layout puesto, move() deja de hacer falta: borralo. Y ya no necesitás pasarle ventana al crear cada widget — el layout se encarga.

Horizontal: un layout adentro de otro

fila = QHBoxLayout()
fila.addWidget(QLabel("Nombre:"))
fila.addWidget(campo_nombre)

layout = QVBoxLayout()
layout.addLayout(fila)            # ← addLayout, no addWidget
layout.addWidget(boton)
Los layouts se anidan: una columna que adentro tiene filas. Así se arma cualquier interfaz, por más compleja que parezca.

Grilla: fila y columna

grilla = QGridLayout()
grilla.addWidget(QLabel("Nombre:"), 0, 0)   # fila 0, columna 0
grilla.addWidget(campo_nombre,      0, 1)   # fila 0, columna 1
grilla.addWidget(QLabel("Edad:"),   1, 0)   # fila 1, columna 0
grilla.addWidget(campo_edad,        1, 1)
Acá addWidget lleva dos números más: fila y columna. Se empieza a contar desde 0, como en las listas.
Desafío · rehacé el formulario con layouts
        Mi aplicación

Nombre: [____________]

Edad:   [____________]

        [ ACEPTAR ]
  • Sin un solo move().
  • Agrandá la ventana con el mouse: ahora todo se acomoda solo.
  • Resolvelo con QGridLayout, o con un QVBoxLayout que contenga dos QHBoxLayout. Las dos son válidas — probá las dos y quedate con la que te resulte más clara.
Investigá

¿Qué hace layout.addStretch()? ¿Y layout.addSpacing(20)? Probalos en distintos lugares de tu layout y mirá qué cambia.

08

PyQt + POO

Acá se junta todo lo que ya sabés

Tu formulario ya tiene variables sueltas, funciones sueltas y widgets sueltos. ¿Qué pasa cuando sean cincuenta?

La idea

Una ventana es una cosa: tiene estado (qué escribió el usuario, cuántos clics lleva) y comportamiento (saludar, limpiar, calcular). Eso es exactamente un objeto. Entonces la escribimos como una clase, igual que Personaje o Jugador.

class Ventana(QWidget):        # HERENCIA: nuestra Ventana ES UN QWidget

    def __init__(self):
        super().__init__()       # que QWidget haga lo suyo primero
        self.setWindowTitle("Mi aplicación")
Mirá bien: no hay nada nuevo. Herencia y super() son los mismos de la clase 2. Lo único distinto es que la clase de la que heredamos no la escribimos nosotros: viene de PyQt.
En PyQtEs lo que ya sabías
QWidgetUna clase — hecha por otra persona, pero una clase común y corriente.
VentanaNuestra clase, que hereda de QWidget: ES UN QWidget, más lo nuestro.
super().__init__()Lo mismo que en Jugador: dejar que el padre se inicialice antes de agregar lo propio.
selfLa ventana concreta con la que estamos trabajando.
self.campo_nombreAtributo: el estado del objeto. Por eso lo ven todos los métodos.
def saludar(self)Método: el comportamiento del objeto.

El formulario, ahora como objeto

import sys
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel,
                             QLineEdit, QPushButton, QVBoxLayout)


class Ventana(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Mi aplicación")
        self.resize(320, 200)

        # los widgets son atributos: self.algo
        self.campo_nombre = QLineEdit()
        self.boton = QPushButton("Saludar")
        self.resultado = QLabel("")

        layout = QVBoxLayout()
        layout.addWidget(QLabel("Nombre:"))
        layout.addWidget(self.campo_nombre)
        layout.addWidget(self.boton)
        layout.addWidget(self.resultado)
        self.setLayout(layout)

        self.boton.clicked.connect(self.saludar)   # un método, no una función suelta

    def saludar(self):
        nombre = self.campo_nombre.text()
        self.resultado.setText(f"¡Hola {nombre}!")


app = QApplication(sys.argv)
ventana = Ventana()
ventana.show()
sys.exit(app.exec())
Las últimas cuatro líneas son idénticas a las del primer experimento. Lo único que cambió es que ahora Ventana() es nuestra clase.
Sin clase

La función saludar usaba variables globales. Funcionaba... hasta que el programa creciera.

Con clase

self.campo_nombre es un atributo: todos los métodos lo ven, sin globales y sin pasarlo por parámetro.

Para recordar

PyQt no reemplaza la POO que aprendimos. PyQt está hecho de objetos, y nosotros organizamos nuestro programa con clases propias. Es la misma herramienta de siempre, aplicada a algo nuevo.

Probá
  • Agregá un método limpiar() que vacíe el campo y el resultado, y un segundo botón que lo llame.
  • Agregá un atributo self.clics = 0 y contá cuántas veces saludaron. ¿Dónde lo inicializás? ¿Dónde lo aumentás?
  • Sacale el self. a self.campo_nombre en el __init__ (dejalo como variable local) y ejecutá. ¿Qué error da saludar? ¿Por qué?
09

Desafío guiado

Tu primera aplicación propia, de punta a punta

Construí «Mi primera aplicación»

El tema lo elegís vos. Lo que tiene que tener, sí o sí:

□Una ventana con un título puesto por vos.
□Al menos 3 widgets distintos.
□Un botón.
□Un campo de texto donde el usuario escriba algo.
□Una interacción: el clic tiene que cambiar algo en pantalla.
□Todo organizado con un layout, sin move().
□Una clase propia para la ventana.

Todo lo demás es libre: los textos, los tamaños, los nombres de las variables, cómo se distribuyen los widgets, qué hace el botón. No copies el ejemplo de la sección 8 tal cual — partí de él y convertilo en algo tuyo.

Si no se te ocurre qué hacer

Un contador de repeticiones de gimnasio. Un sorteador de nombres. Un generador de contraseñas. Un «¿qué como hoy?». Un calculador de promedio de notas. Cualquier cosa que reciba algo, haga una cuenta y muestre un resultado.

Cuando algo no funcione
  • No aparece la ventana → ¿pusiste show() y app.exec()?
  • No aparece un widget → ¿lo agregaste al layout con addWidget()?
  • El botón no hace nada → ¿pusiste connect sin paréntesis en la función?
  • NameError dentro de un método → ¿te faltó el self.?
  • ImportError → ¿agregaste ese widget a la línea del import?
10

Misión de investigación 🔎

La parte más importante de la guía

Ninguna de estas respuestas está en esta guía. A propósito. Nadie sabe PyQt de memoria: se investiga cada vez que hace falta. Elegí al menos cuatro y resolvelas con código que funcione, no solo leyendo.

Misión 01

¿Cómo cambio el color de fondo de una ventana?

Misión 02

¿Cómo cambio el tamaño de la fuente de una etiqueta?

Misión 03

¿Cómo le cambio el tamaño a un botón?

Misión 04

¿Cómo muestro una imagen en la ventana?

Misión 05

¿Cómo muestro un mensaje emergente? ¿Qué es QMessageBox?

Misión 06

¿Cómo evito que la ventana se pueda redimensionar?

Misión 07

¿Qué hace QSpinBox? ¿En qué es mejor que un QLineEdit para pedir una edad?

Misión 08

¿Qué otros widgets existen? Encontrá tres que no vimos y contá para qué sirve cada uno.

Dónde buscar (en este orden)

1 · EditorEscribí boton. y mirá la lista que te ofrece. Es la documentación más rápida que tenés y ya está instalada.
2 · Pythonprint(dir(boton)) lista todo lo que ese objeto puede hacer. help(QPushButton.setText) lo explica.
3 · DocsLa documentación oficial de Qt (doc.qt.io) o de PyQt6. Está escrita para C++, pero los nombres de los métodos son los mismos: aprendé a leerla igual.
4 · BuscadorBuscá en inglés y con la versión: «PyQt6 QLabel change font size». Sumar PyQt6 te ahorra la mitad de los problemas.
5 · ProbarNunca pegues código que no entendés. Pegalo, ejecutalo, cambiale un valor y mirá qué se mueve. Ahí lo entendiste.
Traductor · cuando el ejemplo que encontraste es de PyQt5
  • from PyQt5... → from PyQt6...
  • app.exec_() → app.exec()
  • Qt.AlignCenter → Qt.AlignmentFlag.AlignCenter — en PyQt6 las opciones fijas van con su nombre completo.

Con esas tres reglas, la mayoría de los ejemplos de PyQt5 funcionan en PyQt6. Saber adaptar un ejemplo viejo es una habilidad que vas a usar toda tu carrera.

Lo que realmente estás aprendiendo

No PyQt. Estás aprendiendo a pararte frente a una librería que no conocés, encontrar lo que necesitás y ponerlo a funcionar. Eso sirve para PyQt, para Django, para una librería que todavía no existe.

11

Mini proyecto

Elegí una. Una sola, pero terminada.

Todas se resuelven con lo que ya está en esta guía, más una o dos cosas que vas a tener que investigar. Usá una clase propia y layouts.

Opción A

🧮 Calculadora

Dos números, las cuatro operaciones, un resultado.

QGridLayoutvarios botonesfloat()

A investigar: cómo evitar que se rompa al dividir por cero.

Opción B

🛡️ Registro de personaje

Nombre, clase, nivel y vida. Un botón muestra la ficha completa.

QLineEditQComboBoxQLabel

Conecta directo con la sección 13.

Opción C

🔁 Conversor

Celsius → Fahrenheit, km → millas, pesos → dólares. Elegí uno o hacelos todos con un QComboBox.

QLineEditfloat()f-string

A investigar: cómo redondear el resultado a dos decimales.

Opción D

✅ Gestor de tareas

Escribís una tarea, apretás «Agregar» y aparece en una lista.

QListWidgetaddItem()clear()

A investigar: QListWidget no lo vimos. Y después: ¿cómo se borra la tarea seleccionada?

Opción E

🎒 Inventario de personaje

Nombre del objeto, cantidad y un botón para agregarlo al inventario.

QSpinBoxQListWidgetdict o lista

A pensar: ¿dónde guardás el inventario? ¿Alcanza con lo que se ve en pantalla?

Opción F

💡 La tuya

Si tenés una idea propia del mismo tamaño, hacela. Avisale al profesor qué vas a construir.

libre
Cómo encararlo

Empezá por la ventana vacía. Después un widget. Después el layout. Después el botón. Después la lógica. Ejecutá en cada paso: si escribís todo de una y falla, no vas a saber dónde. Es el mismo método que usaste en Arena de Combate.

12

Desafíos «¿Y si...?»

Si terminaste antes, seguí por acá

¿Y si...?

...agregamos un segundo botón que haga otra cosa?

¿Y si...?

...un botón limpia el formulario y lo deja como recién abierto?

¿Y si...?

...mostramos un mensaje de error cuando falta un dato, en vez de saludar a nadie?

¿Y si...?

...agregamos una imagen: un logo, un avatar, un ícono?

¿Y si...?

...le cambiamos los estilos: colores, fuentes, bordes? (Buscá setStyleSheet.)

¿Y si...?

...guardamos los datos en un archivo y siguen ahí la próxima vez que abrimos la app?

La pregunta que abre la próxima clase

¿Y si nuestra aplicación tuviera varias pantallas?

Un menú de inicio, una pantalla de juego, una de resultados. Todo en un solo archivo de 300 líneas empieza a ser un problema: ¿dónde va cada cosa? ¿Cómo pasamos de una pantalla a otra? ¿Qué parte del código se repite?

No la resuelvas ahora. Si te la hiciste sola, ya llegaste a donde quería llegar esta guía: eso es organización de proyectos y modularización, y es el tema que viene.

13

Relación con nuestro proyecto

Arena de Combate, visto desde acá

Hasta ahora nuestro juego funciona por consola: print() para mostrar, input() para elegir. ¿Qué pasaría si reemplazáramos la consola por una interfaz gráfica?

               ARENA DE COMBATE

        ┌─────────────────────────┐
        │       JUGADOR           │
        │ Vida: ████████░░        │
        │                         │
        │ [ Atacar ]              │
        │ [ Pociones ]            │
        │ [ Inventario ]          │
        └─────────────────────────┘
El mismo juego. Los mismos personajes, el mismo daño, las mismas pociones. Lo único distinto es cómo se ve y cómo se juega.
Respondé antes de escribir una línea de código
  • ¿Qué partes del juego ya tenemos y no habría que tocar?
  • ¿Qué parte tendríamos que cambiar?
  • ¿La lógica del personaje debería desaparecer?
  • ¿Podríamos mantener nuestras clases y cambiar solamente la interfaz?
La lógica · se queda

Personaje, Jugador, Enemigo, Arma, Pocion. Quién tiene cuánta vida, cuánto daño hace un ataque, cuánto cura una poción, si alguien sigue vivo. Nada de esto sabe que existe una pantalla.

La interfaz · se cambia

print() → un QLabel que se actualiza.
input() → un QPushButton que el usuario aprieta.
El while del combate → el bucle de eventos de PyQt.

El descubrimiento

La interfaz y la lógica son dos cosas distintas. Si tus clases no usan print() ni input() — si devuelven resultados en vez de mostrarlos — podés ponerles arriba una consola, un Tkinter, un PyQt o un Pygame sin tocarlas. Es exactamente la diferencia entre print() y return que vimos en la clase 2, y recién ahora se ve para qué servía.

Investigá · en tu propio código

Abrí tu Arena de Combate y buscá los print() que están adentro de los métodos de tus clases. Cada uno de esos es un lugar donde la lógica y la interfaz se mezclaron. ¿Cuántos hay? ¿Cuáles podrías convertir en return?

Para comparar

En la carpeta arena-de-combate/ está el mismo juego resuelto tres veces: juego_consola.py, juego_tkinter.py y juego_pygame.py. Abrilos y mirá qué cambia y qué se mantiene igual entre los tres. Entre consola y Tkinter las clases del principio son casi idénticas; en Pygame cambian un poco más (el Personaje además es un sprite), pero las reglas del juego —vida, daño, pociones— siguen siendo las mismas.

14

Desafío final

Una pantalla de Arena de Combate, en PyQt

Una parte del juego, no el juego entero

No hace falta convertir todo. Una sola pantalla que funcione vale más que un juego entero a medio hacer.

□Mostrar nombre y vida del jugador.
□Mostrar nombre y vida del enemigo.
□Un botón «Atacar».
□Un botón «Usar poción».
□Un QLabel que muestre el resultado de la última acción.

Reutilizá tus clases. Copiá el archivo de tu Arena de Combate al lado del nuevo y hacé from arena import Jugador, Enemigo, Arma. Si no te deja, es porque el archivo original ejecuta el juego al importarlo: eso también es información valiosa sobre cómo está organizado tu proyecto.

Por dónde empezar

1Ventana vacía con una clase ArenaGUI(QWidget). Ejecutala.
2Creá el Jugador y el Enemigo como atributos: self.jugador = Jugador(...).
3Dos QLabel con los nombres y las vidas. Acomodalos con un layout.
4El botón «Atacar» conectado a un método self.atacar().
5Que atacar() llame a tus métodos de siempre y después actualice las etiquetas.
6Recién ahí: la poción, el mensaje de resultado, los colores, el fin del combate.
Si te sobra tiempo
  • ¿Y si la vida se muestra como una barra en vez de un número? (Buscá QProgressBar.)
  • ¿Y si los botones se deshabilitan cuando el combate termina? (Buscá setEnabled.)
  • ¿Y si el historial del combate se va acumulando en un QTextEdit?
15

Checklist final

Marcá solo lo que podrías hacer sin mirar la guía

□Sé instalar una librería.
□Sé importarla.
□Sé crear una ventana.
□Sé agregar widgets.
□Sé organizar widgets con layouts.
□Sé reaccionar a un botón.
□Sé obtener información de un campo.
□Sé modificar un widget.
□Entiendo la idea de eventos.
□Puedo buscar información en la documentación.
□Puedo crear una interfaz utilizando una clase propia.
□Entiendo que PyQt puede trabajar junto con la POO.
Antes de cerrar la guía
  1. Instalar trae la librería a tu computadora; importar la trae a tu programa.
  2. Todo lo que se ve es un widget, y todo widget es un objeto.
  3. El patrón se repite: set...() para cambiar, sin set para preguntar.
  4. Evento → respuesta: algo.clicked.connect(mi_funcion), sin paréntesis.
  5. Los layouts acomodan por vos. move() fue solo para arrancar.
  6. PyQt no reemplaza la POO: nuestra ventana es una clase que hereda de QWidget.
  7. La lógica y la interfaz pueden vivir separadas. Tus clases sobreviven al cambio de pantalla.
  8. No sabés todo PyQt — nadie lo sabe. Sabés cómo averiguar lo que te falta.

Un programador no memoriza una librería.
Aprende a investigarla y utilizarla.

Si terminás pensando «no sé todo PyQt, pero sé cómo empezar a construir con PyQt y cómo averiguar lo que no sé», la actividad cumplió su objetivo.

Guía de exploración · PyQt6 · Técnico Universitario en Programación Continúa Clase 3 (librerías, Tkinter y Pygame) y Arena de Combate