0% encontró este documento útil (0 votos)
3 vistas

Python Nivel 2

Cargado por

uesdagabrielfm
Derechos de autor
© © All Rights Reserved
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
3 vistas

Python Nivel 2

Cargado por

uesdagabrielfm
Derechos de autor
© © All Rights Reserved
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 61

1.

Programación
con Python
Nivel 2
Interfaces Gráficas y
Manejo de Bases de
Datos

Material elaborado por CENEAC Producciones, C.A.


Prohibida su reproducción total o parcial, por medios
impresos o digitales, sin autorización del Autor.
CENEAC Producciones, C.A.

Universidad Central de Venezuela, Facultad de Ciencias, Edif. III, Av. Los Ilustres, Los Chaguaramos, Caracas, Venezuela
Tlf. (58 212) 605-13-14 693-47-38 (telfax) correo [email protected] www.ceneac.com.ve
CENEAC - Programación con Python Nivel 2.

ÍNDICE
1. INTRODUCCIÓN............................................................................................................................. 1
2. REQUISITOS: DESCARGA, INSTALACIÓN Y CONFIGURACIÓN DE LAS
HERRAMIENTAS DE TRABAJO ................................................................................................ 2
2.1. Python .......................................................................................................................................... 2
2.2. PyQT ............................................................................................................................................. 3
2.3. Oracle MySQL Community ........................................................................................................... 4
2.4. PyMySQL ...................................................................................................................................... 5
2.5. PyCharm Community ................................................................................................................... 5
3. GESTIÓN DE EXCEPCIONES ...................................................................................................... 7
3.1. Sentencias try… except… finally ................................................................................................... 8
3.2. Información de contexto .............................................................................................................. 9
3.3. Lanzamiento intencional de excepciones .................................................................................... 9
3.4. Excepciones personalizadas ....................................................................................................... 10
4. PROGRAMACIÓN ORIENTADA A OBJETOS: CLASES, MÉTODOS Y HERENCIA ..... 11
4.1. Creación de una clase en Python ............................................................................................... 11
4.2. Modificadores de acceso para métodos y atributos .................................................................. 12
4.3. Atributos constantes .................................................................................................................. 13
4.4. Constructores ............................................................................................................................. 13
4.5. Herencia ..................................................................................................................................... 15
5. DISEÑO DE INTERFACES GRÁFICAS CON PYQT5 ............................................................ 17
5.1. Mostrar una ventana desde Python........................................................................................... 18
5.2. QMainWindow ........................................................................................................................... 21
5.3. Botones: Command Link Button, Push Button, Tool Button...................................................... 22
5.4. Check Box y Radio Button y Group Box...................................................................................... 23
5.5. Line Edit, Text Edit, Plain Text Edit ............................................................................................. 24
5.6. Etiquetas (Label) ......................................................................................................................... 26
5.7. List Widget ................................................................................................................................. 26
5.8. Combo Box ................................................................................................................................. 28
6. MÉTODOS Y EVENTOS DE PYQT5 .......................................................................................... 30
6.1. Toma de contacto con la gestión de eventos ............................................................................ 30
6.2. Eventos de PyQt ......................................................................................................................... 33
6.3. Métodos de PyQt ....................................................................................................................... 36
7. GESTIÓN DE BASES DE DATOS RELACIONALES CON PYTHON .................................. 43
7.1. Bases de datos centralizadas y distribuidas ............................................................................... 43
7.2. Conectar con MySQL Server desde Python ................................................................................ 43
7.3. Modificaciones ........................................................................................................................... 44
7.4. Consultas .................................................................................................................................... 46
7.5. Acceso a una base de datos SQLite ............................................................................................ 48
7.6. Cargar o crear una base de datos SQLite y operar sobre ella .................................................... 48
8. EJEMPLOS RESUELTOS ............................................................................................................ 51

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor.
CENEAC - Programación con Python Nivel 2.

1. INTRODUCCIÓN

Es bien sabido que Python es un lenguaje tan robusto como potente y parte de toda esa potencia, radica en
su capacidad de expandirse y adaptarse a diferentes entornos sin cambiar su esencia y facilidad de uso.
Justo en ello nos enfocaremos en este curso.
Hoy en día los aplicativos escritos en Python tienen una popularidad sin precedentes, y si bien en el nivel
anterior a este manual, se definieron muchos contenidos inherentes al lenguaje y se explicaron muchas
sentencias útiles, nos hemos limitado a recibir y mostrar datos desde y hacia un terminal dirigido por el
intérprete de Python. Sin embargo, en este curso adoptaremos un enfoque diferente. Mantendremos cada
concepto, cada práctica, cada palabra clave aprendida desde la toma de contacto con Python, hasta la
actualidad, pero los combinaremos con la creación de interfaces gráficas modernas, elegantes y
funcionales.
Una interfaz gráfica de usuario (en adelante, GUI por sus siglas en inglés), es un medio visual para
mostrar y recibir información del usuario, a través de un entorno más atractivo y fácil de entender que un
terminal. Toda aplicación dirigida a usuarios finales, como norma no escrita, debe contar con una GUI con
todas las características del aplicativo en cuestión, si lo que se quiere es garantizar la facilidad de uso y la
reducción de la curva de aprendizaje del software, sin descuidad claro, la elaboración de un manual de
usuario completo y entendible que complemente una GUI intuitiva.
En el curso usaremos PyQT. Es un conjunto de bibliotecas dedicadas a la creación de GUI’s en lenguaje
Python. Consiste en código fuente para Python y bibliotecas compiladas en C++ (lenguaje nativo de QT
Framework). Es de código abierto, multiplataforma, y bastante fácil de usar. Utilizado por cientos de
aplicativos, QT es quizás el Framework más conocido para el diseño de interfaces. Tiene un diseñador
gráfico y una suite de trabajo.
Ahora, no es extraño que una aplicación necesite almacenar de forma temporal o permanente, cierta
información en disco asociada a las funciones que realiza. Para esto, los archivos de texto plano pueden
servir algunas veces, sobre todo para realizar anotaciones o modificar alguna configuración existente, pero
si lo que necesitamos es almacenar configuraciones propias o registros de algún tipo y sobre todo, poder
leerlos de forma rápida y simple, necesitamos algún soporte con un formato que lo permita. Nada mejor
para este fin que una base de datos: fácil de usar, confiable, hermética, segura, ligera y rápida.
En este curso usaremos dos sistemas de gestión de bases de datos relacionales (Relational Database
Management System , en adelante RDBMS):
Oracle MySQL Community, el cual permite todo lo anterior, pero con un elemento adicional importante:
Corre sobre un servidor, esto implica que varias aplicaciones (escritas en Python, Java, C, C++ o cualquier
otro lenguaje para el que exista un conector de MySQL) puedan acceder al mismo tiempo a una misma
base de datos MySQL, cuyo servidor esté corriendo en una ubicación de red accesible y conocida por
todas ellas. Esto es una gran ventaja para sistemas distribuidos, portables y escalables. De ahí su amplia
popularidad en el campo laboral. MySQL Community es gratuito, pero su código es privativo desde su
adquisición por Oracle Corporation.
SQLite es el otro RDBMS. Si hay algo cercano a la eficacia, eso es SQLite. A diferencia de MySQL, no
corre sobre un servidor, por lo que su acceso desde distintas ubicaciones de red, es restringido. Sin
embargo, esta carencia es parte de su fuerte. Al no requerir un servidor para funcionar, el acceso a una
base de datos, no debe pasar por protocolos de red que lo ralenticen. Leer y escribir en una base de datos
SQLite es mucho más rápido que en una MySQL y dicha base de datos estará guardada en un único
archivo con el mismo nombre. SQLite se distribuye sin reconocimiento legal; esto quiere decir que usted
es libre de usarlo, estudiarlo, modificarlo y redistribuirlo con o sin sus modificaciones, incluso bajo
licencia comercial, sin necesidad de un permiso del autor. Es un software de dominio público.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 1
CENEAC - Programación con Python Nivel 2.

2. REQUISITOS: DESCARGA, INSTALACIÓN


Y CONFIGURACIÓN DE LAS HERRAMIENTAS DE
TRABAJO

Empecemos por decir que son varias las cosas que necesitamos. Todas son gratuitas y la instalación de
algunas será más fácil que la de otras. Intentaremos explicar de forma clara y con abundancia de
ilustraciones, la forma de lograr una instalación limpia de todo lo que necesitamos:
 Python. Intérprete y bibliotecas estándar
 Un IDE para programar en Python, recomendado PyCharm Community o Visual Studio 2012 (o
posterior). Ambos son pesados y requieren un equipo de gama media-baja. Para equipos antiguos
es mejor un editor de código fuente como Notepad++ o el propio editor de Python, llamado IDLE
(Incluido en la instalación de Python 2.7 y posteriores).
 PyQT, un conjunto de bibliotecas dedicadas al diseño de GUI’s para Python.
 Oracle MySQL Community, un RDBMS
 PyMySQL, conector de MySQL para las últimas versiones de Python
Por favor siga las instrucciones que a continuación se suministran, en estricto orden para lograr la
instalación y configuración de todo el software necesario.

2.1. Python
Descargue el instalador desde su página oficial:
https://www.python.org/downloads/release/python-351/
Seleccione la versión instalable acorde a su sistema operativo y la arquitectura del mismo. Recuerde que
las versiones x86 son para sistemas de 32 bits y las versiones x86-64, son para sistemas de 64 bits. Inicie
la instalación y verá una imagen como la siguiente:

Figura 1. Instalación de Python (I)

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 2
CENEAC - Programación con Python Nivel 2.

Seleccione la casilla Add Python 3.6 to PATH, esto es para poder ejecutar Python desde un terminal, solo
con escribir su nombre.
Luego seleccione Customize Installation para indicar qué componentes se instalarán y para qué usuarios.
Le recomendamos que deje todas las opciones por defecto y luego pulse Next. Cuando lo haga, por favor
coloque las siguientes opciones:

Figura 2. Instalación de Python (II)

Nota: La casilla Download debugging symbols requiere conexión a internet. Ella descargará los archivos
necesarios para que el depurador de su entorno de desarrollo pueda proveerle mayor información al
momento de ejecutar su aplicación sobre él. Si no posee conexión a internet, no la marque. Si planea
usar Visual Studio 2015 o 2017 para sus aplicativos en Python, es recomendable que marque también la
última casilla: Download debug binaries, recordando que, de igual manera, deberá tener conexión a
internet.

Luego de pulsar Install, iniciará la instalación del Python y al culminar, el instalador nos indicará el
mensaje: Setup was Successful, confirmando así que la instalación concluyó exitosamente. Pulse Close
para cerrar el instalador.

2.2. PyQT
El instalador de PyQT se acopla directamente a su instalación de Python, por lo que éste deberá ser
instalado antes que PyQT. La versión tratada en esta guía es PyQT 5.
Puede descargar PyQT desde acá:
https://sourceforge.net/projects/pyqt/
La instalación es sencilla. Siga los pasos del instalador, siempre seleccionando el botón Next y la
instalación concluirá sin problemas al cabo de unos cuantos segundos.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 3
CENEAC - Programación con Python Nivel 2.

2.3. Oracle MySQL Community


Este es el RDBMS que debemos instalar. SQLite ya viene por defecto con la instalación de Python.
Podemos descargar MySQL de acá:
https://dev.mysql.com/downloads/installer/

Figura 3. Instalación de MySQL

En la parte de abajo aparecen dos enlaces de descarga. El primero es un instalador que descarga todo lo
necesario desde la web. El segundo incluye todo lo necesario para instalar MySQL Server y MySQL
Workbench. Le recomendamos el primero si posee conexión a internet en la máquina de destino, o el
segundo en caso contrario.
En todo caso, inicie el instalador y en los productos a instalar, seleccione los que usted necesite. Para
propósitos del curso, solo necesitamos MySQL Server. Opcionalmente, puede instalar MySQL
Workbench para operar sobre sus bases de datos de forma gráfica, sin embargo, no será usado en este
manual.
Luego de instalar MySQL Server, se iniciará una ventana de configuración de su RDBMS siempre y
cuando no tenga, o haya tenido, una instalación previa de MySQL. En esta ventana, elija un usuario (o
varios) para su base de datos, asígnele permisos y configure una nueva contraseña para el usuario root.
Tenga en cuenta que esta contraseña es la maestra por si ocurriera algún error en su sistema que necesite
acciones especiales o circunstancias en las que no posea permisos suficientes para ciertas operaciones, le
sugerimos que la anote en un lugar seguro.
Luego de configurar usuarios, permisos y contraseñas, continúe con el proceso de configuración, dejando
las opciones por defecto, o configurándolas en tanto sepa la finalidad de cada una.
Una vez concluido el proceso, si dejó las opciones por defecto, MySQL Server se iniciará de ahora en
adelante automáticamente con el sistema, como un servicio de Windows, por lo que, para poder usarlo, no
hará falta iniciarlo manualmente. Consulte la documentación en línea de MySQL Server si desea saber
cómo configurar ésta y otras opciones.

Nota: Es recomendable, que para cada aplicativo exista un sistema de permisos acorde a las actividades
que se van a realizar con la base de datos. Por cuestiones de seguridad, asigne a un usuario, solo los
privilegios necesarios para cumplir con sus funciones.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 4
CENEAC - Programación con Python Nivel 2.

2.4. PyMySQL
Ejecute un símbolo de sistema como administrador, y en él escriba:
“pip install pyMySQL”
Y espere por la instalación.

Figura 4. Instalación exitosa de PyMySQL

2.5. PyCharm Community


Este es el entorno de desarrollo que usaremos para la programación en Python. Puede descárgalo de aca:
https://www.jetbrains.com/pycharm/download/
Inicie el instalador, seleccione la ruta en la que desea instalar el programa y en la siguiente pantalla, elija
la arquitectura de su sistema operativo para crear el acceso directo en su escritorio. En la casilla inferior,
puede elegir si desea que PyCharm sea el aplicativo por defecto para sus módulos Python. Si desea que al
pulsar doble clic en un archivo .py, se inicie el módulo con Python, deje esta opc ión desactivada.

Figura 5. Instalación de PyCharm

Al iniciar PyCharm, puede elegir importar configuraciones de una instalación previa de PyCharm, o
iniciarlo desde cero. Luego de seleccionar la opción de su preferencia, aparecerá una ventana de

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 5
CENEAC - Programación con Python Nivel 2.

bienvenida, pidiéndole elegir el tema del IDE, el mapeado del teclado y el color de fuente del editor de
código fuente.

Figura 6. Configuración de PyCharm Community

Luego de un reinicio, puede pulsar la opción “New Project” para crear un juego proyecto. Seleccione la
ruta en la que lo guardará y espere un poco. Solo por ser el primer inicio, PyCharm analizará el directorio
de Python en busca de los archivos fuente que contiene, y los indexará. El avance de este proceso se puede
observar detalladamente haciendo clic en la parte inferior derecha del IDE, en el indicador “x process
running”.
Cree un nuevo archivo .py, haciendo clic derecho en el nombre de su proyecto y luego en New  Python
File. Para ejecutar este archivo por primera vez, haga clic en Run  Run…, luego seleccione el archivo y
éste se ejecutará. De ahora en adelante, para ejecutarlo, simplemente pulse el botón de flecha verde que
está arriba a la derecha del IDE, o directamente pulse Mayús+F10.
Una vez concluido el proceso, puede utilizar el IDE con todas sus funciones. Tómese un tiempo para
familiarizarse con ellas. Ya posee todas las herramientas configuradas y listas para funcionar.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 6
CENEAC - Programación con Python Nivel 2.

3. GESTIÓN DE EXCEPCIONES

Cuando escribimos código en Python, debemos adaptarnos a su sintaxis, si no lo hacemos, al ejecutar


recibiremos un error en tiempo de ejecución. Los errores de sintaxis terminan abruptamente la ejecución
del programa. En estos casos, el intérprete nos dice el error ocurrido, el módulo, la línea y el carácter
donde se detectó.
Sin embargo, no todos los errores son de sintaxis, algunos son errores lógicos, o de ejecución, que solo
ocurren en función de factores que no se conocen con anterioridad. Algunos errores lógicos son: División
por cero, entrada errónea, uso de variable no definida, conversión implícita… etc.
Cuando el intérprete ejecuta una línea que contiene un error lógico, se genera una excepción. Una
excepción es un objeto que se lanza al intérprete y que, de no ser capturado, termina la ejecución del
programa en esa misma línea, sin ejecutar las que le siguen.
Ejemplo 1: Excepción no controlada por división entre cero
def dividir(n1,n2):
return n1 / n2
if __name__ == "__main__":
dividir(10, 0)
Este código producirá una salida similar a la siguiente:
Traceback (most recent call last):
File "D:\PROYECTOS_PROGRAMACION\Python\CursoN2\Excepciones\NoControlada.py", line 5, in
<module>
dividir(10, 0)
File "D:\PROYECTOS_PROGRAMACION\Python\CursoN2\Excepciones\NoControlada.py", line 2, in dividir
return n1 / n2
ZeroDivisionError: division by zero
Ejemplo 2: Excepción de conversión implícita
if __name__ == "__main__":
cadena = "43FFDB"
numero = int(cadena)
print(numero)
La salida sería esta:
Traceback (most recent call last):
File "D:\PROYECTOS_PROGRAMACION\Python\CursoN2\Excepciones\NoControlada.py", line 4, in
<module>
numero = int(cadena)
ValueError: invalid literal for int() with base 10: '43FFDB'

Para evitar una excepción, el código anterior se pudo haber cambiado por este:
if __name__ == "__main__":
cadena = "43FFDB"
numero = int(cadena,16)
print(numero)
Así, la conversión se haría en hexadecimal y no en decimal.
Todo programa en Python debe poseer un correcto manejo de excepciones, para evitar que cualquier error
del usuario pueda comprometer la estabilidad de nuestro software.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 7
CENEAC - Programación con Python Nivel 2.

3.1. Sentencias try… except… finally


Nos ayudan a capturar excepciones y evitar que éstas interrumpan la ejecución de la aplicación. Todo
bloque try, debe tener un bloque except, un bloque finally, o ambos.
En el bloque try, se debe colocar todo código que sea susceptible a generar excepciones. Si alguna ocurre
en este bloque, la ejecución de las líneas inferiores del mismo bloque es suspendida, y la ejecución
continúa en el bloque except. Si no se genera excepción alguna, éste no se ejecutará.
Por su parte, finally es un bloque que contiene todo código que queramos ejecutar siempre sin importar si
se genera una excepción o no.
Estas sentencias deben usarse solo como último recurso. Como primera línea de defensa, debemos usar
comparaciones simples, cuyo resultado pueda determinar la existencia de una excepción en un futuro. Es
decir, en lugar de usar un try por cada división, usemos mejor un if que compare si el divisor es cero antes
de hacer la operación.
Como sea, siempre hay situaciones que no podemos prevenir (un error interno de la base de datos, una
entrada incorrecta del usuario, errores de permisos… etc.). Para ellos está ideado el bloque try… catch…
finally. Eso no quiere decir, que no podamos usar estas sentencias para errores previsibles.
Ejemplo 3: Uso de try… except… finally para evitar un cierre forzoso
if __name__ == "__main__":
try:
n1 = int(input("Ingrese dividendo: "))
n2 = int(input("Ingrese divisor: "))
print("Resultado: ", n1/n2)
except ValueError:
print("Error al ingresar valores. Ingrese solo valores enteros")
except ZeroDivisionError:
print("No puede colocar \"0\" como divisor.")
except:
print("Error desconocido")
finally:
print("Esto se ejecutará siempre")

Un ejemplo interesante. Todo el código susceptible a generar excepciones, debe colocarse en el bloque
try. Si se genera una excepción en él, no se ejecutarán las líneas que estén por debajo de la que generó la
excepción y que se encuentren en el mismo try. En su lugar, se ejecutarán las sentencias correspondientes
al except que la atienda. Si se genera una excepción de tipo ZeroDivisionError, entonces se ejecutarán
solo las sentencias de ese except. Si no conocemos el nombre de la excepción, o no es relevante mostrar
un mensaje personalizado, puede usar except sin ningún tipo de excepción.
Sin importar si se genera o no una excepción, las instrucciones que haya en el bloque finally siempre se
ejecutarán.
Si no hay un except genérico y ninguno de los except cubre el error que se generó, la excepción saltará los
controles del try y terminará el programa. Si hay un bloque try, que contiene un finally, pero ningún
bloque except, y se genera una excepción, se interrumpirá igualmente el boque try, se ejecutarán las
instrucciones del finally, pero igualmente terminará el programa a causa de la excepción. Es decir, solo el
bloque except captura excepciones.
El bloque except no solo puede tener una excepción, puede tener varias, separadas por comas.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 8
CENEAC - Programación con Python Nivel 2.

Nota: Si queremos que una excepción no termine el programa, pero aun así no queremos tomar
acciones al respecto, basta con colocar un pass, como única sentencia del bloque except.

3.2. Información de contexto


Las excepciones son objetos. Los objetos tienen atributos y métodos. Cuando las excepciones ocurren, se
crean nuevos objetos y se les da valor a estos miembros. En un except tenemos acceso a ellos:
Ejemplo 4: Obtener información de una excepción
try:
n1 = 10
n2 = "20"
n3 = n1 + n2
except Exception as ex:
print(ex.args)
Se utiliza una clase llamada Exception. Esta es la clase base de todas las excepciones y posee un atributo
llamado args, que contiene información acerca del error ocurrido.

3.3. Lanzamiento intencional de excepciones


Ya sabemos cómo capturarlas, pero también se pueden lanzar excepciones adrede. La cuestión es, para
qué. Una correcta estructura de excepciones, puede aumentar la robustez de nuestras clases. Cuando otro
programador o equipo las utilice, se pueden usar para que éstos puedan responder correctamente a los
posibles errores que puedan presentarse en nuestros módulos y en los cuales no tengamos información
suficiente para responder a ellos. En tal caso, usamos excepciones: para delegar la responsabilidad de
atender un error, al módulo que esté utilizando el nuestro.
La palabra clave para lanzar una excepción es raise.
Ejemplo 5: Lanzamiento de excepciones
def pedir_numero():
nombre = input("Ingrese nombre: ")
for i in nombre:
if i.isnumeric():
raise Exception("No se permiten números en los nombres")

if __name__ == "__main__":
pedir_numero()

De nuevo, usamos a Exception como clase para nuestro error. Al ejecutar el ejemplo anterior y colocar en
un número en el texto solicitado, se generará una salida similar a la siguiente:

Ingrese nombre: C4RL05


Traceback (most recent call last):
File "D:/PROYECTOS_PROGRAMACION/Python/CursoN2/Excepciones/Lanzamiento.py", line 8, in
<module>
pedir_numero()
File "D:/PROYECTOS_PROGRAMACION/Python/CursoN2/Excepciones/Lanzamiento.py", line 5, in
pedir_numero
raise Exception("No se permiten números en los nombres")
Exception: No se permiten números en los nombres

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 9
CENEAC - Programación con Python Nivel 2.

Y como es de esperarse, al no haber un except, el programa termina con código fallido.

3.4. Excepciones personalizadas


Ya vimos que podemos generar excepciones a voluntad. Pero en diversas ocasiones nos conviene generar
nuestras propias excepciones, no solo a la propia clase Exception o a sus clases hijas prestablecidas.
Toda clase hija de BaseException es considerada como una clase que puede ser lanzada. Si no hereda de
ella, generará otra excepción: TypeError.
Ejemplo 6: Generar excepciones propias
class Propia(BaseException):
def __init__(self, cad = "Ha ocurrido un error", n = 0):
self.valor = cad + ". Código de error: " + str(n)

def __str__(self):
return self.valor

if __name__ == "__main__":
n = int(input("Numero: "))
if n == 1:
raise Propia("Error en entrada",10)
else:
raise Propia()
Se solicita un valor por teclado. Si este valor es 1, se genera una excepción propia por defecto. Si es
distinto a 1, se genera una excepción con parámetros solicitados. Estos parámetros van a una clase que
nosotros creamos, llamada Propia. Esta clase recibe dos parámetros opcionales en su constructor. Estos
parámetros serán el código del error y su texto. Note que se sobrescribe el método __str__ con la finalidad
de mostrar en pantalla el texto correcto cuando se lance la excepción. Este método debe devolver una
cadena de caracteres con el texto que se quiera mostrar.
Si colocamos un número distinto a 1, el resultado sería parecido a este:
Numero: 50
Traceback (most recent call last):
File "D:/PROYECTOS_PROGRAMACION/Python/CursoN2/Excepciones/ExcepcionesPropias.py", line 15,
in <module>
raise Propia()
__main__.Propia: Ha ocurrido un error. Código de error: 0
Nota: Si esta clase llamada Propia, tuviera otros atributos y métodos, se pueden usar desde el except,
como información de contexto. Actualmente, solo se tiene acceso al atributo valor, pues no existe algún
otro.
Aparte, Qt genera excepciones propias y PyCharm no nos avisará cuando ocurran. Si estamos iniciando
en PyQt5, encierre en un bloque try ese código que hace que su programa termine sin razón y muestre el
texto de la excepción en la salida estándar. Este es un consejo valioso si no quiere pasar horas revisando
el código en busca de la razón por la que falló su código. Le pedimos por favor que no subestime esta
sugerencia.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 10
CENEAC - Programación con Python Nivel 2.

4. PROGRAMACIÓN ORIENTADA A
OBJETOS:
CLASES, MÉTODOS Y HERENCIA

Cuando hablamos de programación orientada a objetos (en adelante POO), hablamos de un paradigma que
cambia por completo, la manera usual de hacer las cosas en la programación procedimental. Se trata de un
paradigma orientado a la claridad del código a través de su división por paquetes y clases. En este sentido,
cada ente manipulable por el lenguaje es un objeto. Una variable, una constante o un método son ejemplos
perfectos de lo que es un objeto.
Hablar de POO es hablar de clases. Una clase es un modelo, una plantilla para la creación de un objeto.
Podemos reducir el concepto y pensar en una clase como un nuevo tipo de dato del que podemos crear
variables.
Intentemos ver esto desde otro punto de vista. Tomemos los papeles de un arquitecto que, en pleno auge
de su carrera, tiene en sus manos la construcción de un edificio imponente. Para ello, nuestro arquitecto
debe elaborar un plano que contenga todas las especificaciones de la estructura. Este plano fija todas las
directrices para la construcción del edificio. Si hacemos una analogía con nuestros menesteres, podemos
asociar este plano, con una clase, y al edificio (entidad física basada en el plano) con el propio objeto. De
la misma forma en la que la elaboración de un plano, no implica necesariamente, la existencia de un
edificio basado en él, la existencia de una clase, no implica la existencia de un objeto basado en ella.
Puede haber cualquier cantidad de objetos basados en una clase, por lo que evidentemente, antes de crear
el objeto, debe existir la clase que lo represente, pero no al revés.
Sabemos lo que es una clase. Pero no un objeto. Un objeto es una instancia de una clase. Es una entidad
que posee un estado y un comportamiento determinado. El estado de un objeto, varía en función de los
atributos que tenga su clase y su comportamiento será el que establezcan los métodos de la misma.

4.1. Creación de una clase en Python


Python es un lenguaje híbrido. Él soporta la POO, tanto como la funcional. Podemos decir que es un
lenguaje multiparadigma. Esto es importante si tenemos en cuenta que, si bien la POO ayuda a mantener
nuestro código ordenado y legible, ésta no es obligatoria. Para crear una clase en Python, se usa la palabra
clave class, seguido del nombre de la clase, luego dos puntos y abajo, luego de su respectiva tabulación, se
especifican sus atributos y métodos (o la palabra reservada pass para dejarla temporalmente en blanco).
Ejemplo 7: Creación de clases en Python
class Calculadora:
op1, op2 = 0, 0

def sumar(self):
return self.op1 + self.op2

def restar(self):
return self.op1 - self.op2

def multiplicar(self):
return self.op1 * self.op2

def dividir(self):
if not self.op2:

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 11
CENEAC - Programación con Python Nivel 2.

raise ArithmeticError("División por cero")


else:
return self.op1 / self.op2
objeto = Calculadora()
objeto.op1 = 10
objeto.op2 = 0
print(objeto.dividir())

En el ejemplo anterior, se crea una clase llamada Calculadora. Esta clase tendrá dos atributos. Los
atributos de una clase, son variables declaradas adentro de ella y en nuestro caso, son Op1 y Op2
respectivamente. Cada uno de ellos, inicializado en cero.
Luego de los atributos hay cuatro funciones. De ahora en adelante, los llamaremos métodos, por estar
adentro de una clase. Estos métodos definen el comportamiento de un objeto basado en esa clase. Estos
métodos regresan un valor igual al resultado de la operación aritmética que representan. Así, suma,
regresa la adición de los dos atributos de la clase, resta devuelve la substracción, etc.
Prestemos especial atención a dos cosas. Primero, note que usamos la palabra self como primer parámetro
del método y luego, la usamos antes de los nombres de los atributos, para poder acceder a ellos. Esto es
porque cuando creamos atributos en una clase y usamos solo su nombre en un método, realmente no
estamos accediendo al atributo, sino creando una nueva variable con ese nombre, que será visible solo
para el método. Por ende, para diferenciar variables locales, de los atributos de la clase, cuando éstos
tienen el mismo nombre, se usa la palabra self, seguida de un punto y luego, el nombre del miembro de la
clase al que queremos acceder.
En cuanto al parámetro, es obligatorio que los métodos de una clase tengan a self como primer parámetro.
Esto no es solo una cuestión formal. Self está allí para cuando se quiera llamar al método sin utilizar
el objeto que lo contiene. De ser así, debe especificarse el parámetro self antes que el resto de los
parámetros. En todo caso, self contendrá una referencia a la propia clase, para poder acceder a los
atributos y métodos del objeto. Si se quiere llamar a un método de una clase, desde un objeto existente,
puede omitirse el parámetro self.
Como segunda aclaratoria, tenemos a raise. Es una palabra que lanza una excepción que, de no ser
capturada, termina súbitamente el programa con el mensaje y motivo que elijamos. En este caso, el error
es que la división por cero no está definida y por ende, no podemos mostrar un resultado certero, así que
lanzamos la excepción para que la persona que usó nuestra clase, pueda responder adecuadamente a ella.
Por último, se muestra la forma correcta de crear un objeto a partir de una clase. Se escribe el nombre de
la variable y luego del operador de asignación, se escribe el nombre de la clase, seguido de una pareja de
paréntesis. De esta forma, tenemos un objeto creado, con el nombre de la variable.
Para acceder a los miembros del objeto, se utiliza un punto. Escribimos el nombre del objeto, un punto y
luego el atributo o método al que quiero acceder.

4.2. Modificadores de acceso para métodos y atributos


Es usual en otros lenguajes que soportan POO, como C++, C#, Java o Delphi, que los métodos y atributos
de una clase puedan ser públicos, privados o protegidos, para garantizar o evitar que otra clase pueda tener
acceso a dichos miembros.
En Python no hay modificadores de acceso, todos los miembros de una clase son públicos. Existe una
convención muy usada, tanto por los desarrolladores del lenguaje, como los que lo utilizan, y es anteponer
un “_” antes del nombre del atributo o método, para aclarar que no hay necesidad de usarlo fuera de la

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 12
CENEAC - Programación con Python Nivel 2.

clase. Claro, esto no impide que otra clase pueda usar atributos o métodos declarados de esta forma, pero
sirve como indicativo para evitar que suceda.

4.3. Atributos constantes


Así como los modificadores de acceso, suele haber atributos constantes en las clases de otros lenguajes.
Python no soporta el uso de constantes. Aun así, una variable escrita en mayúsculas sostenidas, es
interpretada como constante y se entiende que su valor, no debería ser modificado (aunque se pueda).
Ejemplo 8: Creación de clases en Python
import math
class FiguraGeometrica:
d1, d2 = 0, 0

def area_cuadrado(self):
return self.d1 * self.d2

def area_circulo(self):
return math.pi * pow(self.d1, 2)

def area_rectangulo(self):
return self.d1 * self.d2

def area_triangulo(self):
return (self.d1 * self.d2) / 2

def funcion_no_definida(self):
pass
En el ejemplo anterior podemos ver la declaración de un método para el que aún no existe una definición,
o cuerpo. También obsérvese el uso del paquete math, para usar la constante PI.

4.4. Constructores
Son métodos llamados automáticamente cuando se crea un nuevo objeto de una clase. Estos métodos son
muy útiles y su finalidad incluye, pero no se limita a:
- Darle un valor válido a cada atributo de la clase.
- Obligar al usuario de esta clase, a pasarle todos los datos que necesita para funcionar.
Para indicarle a Python que un determinado método es un constructor, debemos llamarlo __init__:
Ejemplo 9: Creación de constructores
class A:
lista = []
def __init__(self, p):
self.lista = p

def mostrar_lista(self):
for i in self.lista:
print (i)
En esta clase hay un constructor que recibe un parámetro llamado p. Cuando una clase no define un
constructor propio, Python le crea uno por defecto, sin parámetros y sin sentencias, solo para permitirnos
la creación de un objeto de la siguiente manera:

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 13
CENEAC - Programación con Python Nivel 2.

nuevo_objeto = NombreClase()
Sin embargo, cuando una clase define un constructor (como en el ejemplo), no hay constructor por
defecto, y si el constructor propio no puede recibir cero parámetros, es obligatorio pasarle al objeto, una
lista de parámetros tal, que coincida con la lista de parámetros solicitado por el constructor propio. En el
ejemplo anterior, estamos obligados a pasar un parámetro al constructor para evitar un error del intérprete.
Ampliemos el ejemplo anterior un poco:
Ejemplo 10: Constructores con parámetros
class A:
def __init__(self, p1, p2=-1):
if p2 != -1:
self.lista = [p1] * int(p2)
elif type(p1) is list or type(p1) is tuple:
self.lista = list(p1)
else:
print("ERROR, tipo de p1 es", type(p1))
return
print("Lista:\n", self.lista)

parametros = [5, 10]


objeto = A([8,9,0,67,4,3,54,6,7,31]) # Válido
objeto = A((2,4,6,8,4)) # Válido
objeto = A(8,15) # Válido
objeto = A(*parametros) # Válido
objeto = A("CD", 10) # Válido
objeto = A() # Inválido
objeto = A(5) # Inválido
objeto = A(8,9,3) # Inválido
objeto = A({4,6,7,4,3}) # Inválido
objeto = A(4, [4,6,8]) # Inválido
objeto = A("CD", "AF") # Inválido

Antes de explicar la parte de este ejercicio que nos concierne, debemos aclarar un par de cosas. Primero
está el uso de type. Esta función nos regresa el tipo de la variable. Si usamos el operador is con él,
podemos compararlo con un tipo conocido. La sentencia if que la utiliza, puede ser interpretada como “Si
el tipo de p1 es lista, o el tipo de p1 es tupla, entonces…”. Y es así, en caso de que p1 sea de alguno de
esos dos tipos, creamos una nueva lista en el atributo homónimo de esa clase. Esto se hace para evitar
conversiones inválidas.
El segundo parámetro del método es por defecto, un entero. Si el constructor es llamado con un solo
parámetro, éste intentará copiar en una lista, los elementos de este parámetro. Si se le pasan dos
parámetros, entonces intentará crear una lista nueva de tantos elementos como indique p1, y cada uno de
esos elementos será igual a p2. Es decir, si los parámetros suministrados al método son 5 y 4, al imprimir
la lista, obtendremos una lista de cuatro elementos, llena de números cinco. La idea es multiplicar una lista
con un único elemento (el cinco) por cuatro. Esto se logra con la siguiente sentencia:
[ elemento ] * cantidad
De seguir siendo 5 y 4, los enteros suministrados, la lista sería:
[5, 5, 5, 5]
Ahora, en el ejemplo anterior se indican las formas válidas e inválidas de llamar al constructor. El
constructor se llama al crear el objeto. Veamos el resultado con cada una de las llamadas:

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 14
CENEAC - Programación con Python Nivel 2.

objeto = A([8,9,0,67,4,3,54,6,7,31]) # Válido


Se crea una nueva lista basada en la que se suministró en el parámetro.
objeto = A((2,4,6,8,4)) # Válido
Se crea una nueva lista con los mismos elementos de la tupla suministrada.
objeto = A(8,15) # Válido
Se crea una nueva lista con quince números ocho.
objeto = A(*parametros) # Válido
Se llama al método con dos parámetros, esos dos parámetros están en la lista suministrada: 5 y 10.
objeto = A("CD", 10) # Válido
Se crea una nueva lista con 10 string. Esos 10 elementos serán “CD”.
objeto = A() # Inválido
Error: No se puede llamar al constructor sin parámetros.
objeto = A(5) # Inválido
Error: No se puede llamar al constructor con un único parámetro, de tipo entero.
objeto = A(8,9,3) # Inválido
Error: El constructor no acepta tres argumentos.
objeto = A({4,6,7,4,3}) # Inválido
Error: El constructor no acepta un diccionario como parámetro.
objeto = A(4, [4,6,8]) # Inválido
Error: No se puede llamar al constructor con un entero como primer parámetro y una lista como segundo.
objeto = A("CD", "AF") # Inválido
Error: El segundo parámetro no puede ser un string no convertible a entero.

4.5. Herencia
Es una facultad que tienen las clases de poder utilizar como propios, los métodos y atributos de una o más
clases. Esto es importante para reutilizar código existente y evitar su reescritura. La herencia es uno de los
pilares de la POO. Su uso es universal en todos los lenguajes considerados orientados a objetos. Acá
explicaremos su uso.
Recordemos el ejemplo del arquitecto. Este profesional logró construir exitosamente el edificio y con base
en su éxito, recibe nuevas ofertas de empleo en las que debe construir edificios similares, pero no iguales
al primero que levantó. El nuevo edificio consiste en uno igual al anterior, pero con una piscina en el
último piso y un par de salones de fiesta en la planta baja. ¿Debería el arquitecto, elaborar un nuevo plano
desde cero para esta nueva obra? La respuesta es no. El plano anterior sirve, pues el edificio nuevo está
basado en el antiguo, solo que con varias modificaciones.
Entonces, si lo que se busca es eficiencia y reducción de costos, se utiliza el plano anterior y se le añaden
las modificaciones pertinentes. La creación del nuevo edificio consiste en la construcción del edificio
anterior y adicionalmente, en una piscina y dos salones de fiesta. De esta forma, solo se tuvo que elaborar
planos para estos objetos y no para el edificio entero. Establezcamos de nuevo una analogía de este
ejemplo, con la programación orientada a objetos, el plano viejo sería la clase base (también llamada
padre), y la subclase (o clase hija) sería el plano nuevo. De la misma forma en la que éste último, solo

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 15
CENEAC - Programación con Python Nivel 2.

debe contener la piscina y los dos salones de fiesta, la clase hija solo debe tener los métodos y atributos
inherentes a ella y no los de la clase base, pues al heredar de ella, ya los contendrá de forma implícita.
Veamos un ejemplo práctico a continuación, donde tenemos una clase llamada Animal y de ella heredarán
varias clases.
Ejemplo 11: Uso de herencia en Python
class Animal:
hábitat = ""
cría = "vivíparo"

class Ave(Animal):
color_alas = ""
altura_maxima = ""

class Pez(Animal):
profundidad_maxima = -500
respiración = "branquial"

class Mamífero(Animal):
cantidad_mamas = 4

class Perro(Mamífero):
raza = ""
nombre = ""
color_pelaje = ""

class Gato(Mamífero):
raza = ""
nombre = ""
tamaño = 0

atún = Pez()
atún.hábitat = "Acuático"
atún.cría = "Ovíparo"

Una clase que hereda de otra, debe especificar entre paréntesis, una o más clases (si son varias, separarlas
por comas), de las cuales quiere tomar todos sus atributos y métodos. Al hacerlo, esta clase hija contendrá
un conjunto de métodos y atributos heredados de otras clases, más los suyos propios. Cuando una clase
hereda de otra, y esta otra hereda a su vez, de una clase más, la clase hija contendrá los métodos y
atributos de su clase base y de toda la jerarquía a la que ésta pertenezca.
Volviendo al ejemplo anterior, la jerarquía de clases completa sería la siguiente:

Ave
Gato
Animal Mamífero
Perro
Pez

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 16
CENEAC - Programación con Python Nivel 2.

5. DISEÑO DE INTERFACES GRÁFICAS CON


PYQT5

¿Cómo sería nuestra experiencia enfrente de un ordenador si los aplicativos que usamos con frecuencia
operaran siempre por líneas de comandos? ¿Qué éxito tendría una aplicación moderna destinada a
usuarios finales si ésta no tuviera una interfaz gráfica? Las respuestas a ambas preguntas compiten por ser
la más desalentadora. Es natural, e incluso imperativo que el atractivo de una aplicación, vaya de la mano
con su popularidad, por lo que en este manual veremos cómo aplicar en nuestras creaciones, diseños que
faciliten la comprensión y uso de las mismas.
Si bien, la creación de interfaces gráficas puede hacerse solo a código, o todo con un diseñador de GUI,
nosotros usaremos una combinación de ambos. Como bien se ha dicho, trabajaremos con QT Framework.
Es un conjunto de clases diseñadas originalmente para C++, pero que podemos usar en Python, sin
sacrificar rendimiento. Ahora, Python y PyQT deberán estar instalados en cada PC a la que queramos
distribuir nuestra aplicación, así que es bueno tenerlo en cuenta.
El diseñador que usaremos se llama Qt Designer y puede encontrarlo entre sus programas instalados. Qt
Designer le preguntará por el tipo de interfaz que desea crear. Seleccione Main Window y pulse Create. La
vista del programa será la siguiente:

Figura 7. Vista principal de Qt Designer

La barra que está justo debajo del menú, es la barra de archivo y layout. No la usaremos más que para
guardar archivos, pero es muy útil para establecer el alineamiento automático de los controles, a la
ventana a la que pertenecen. Se sugiere investigar su uso.
La lista de la izquierda contiene todos los controles que Qt soporta. Los controles son componentes que
cumplen alguna función. Entre estos controles, están varios reconocibles por un usuario estándar, como
los campos de texto, botones, etiquetas, listas, etc.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 17
CENEAC - Programación con Python Nivel 2.

La ventana del centro es la ventana del diseñador, puede arrastrar cualquier control de la lista a la ventana
y posicionarlo donde prefiera. Ésta a su vez, también es un control, con eventos y propiedades
características.
Por último, tenemos a la derecha, tres ventanas acomodadas una debajo de otra. De arriba abajo, está el
inspector de objetos, donde aparecen todos los controles colocados en nuestra ventana, junto a su tipo y su
nombre. Para cambiar el nombre de un control, selecciónelo en el inspector y pulse F2.
Luego está el editor de propiedades. Vamos a darle un espacio mayor a esta herramienta, pues es
imprescindible un dominio de ella para poder culminar exitosamente una aplicación con GUI. Los objetos
gráficos en Qt, tienen propiedades. Una propiedad es una característica, o atributo de un objeto que
especifica la manera en la que éste se comportará.
De la misma manera en la que una persona tiene nombre, edad, sexo y dirección, una ventana en Qt tiene
ancho, alto, título, fuente, etc. Un campo de texto tiene fuente, color de texto, texto, ancho, alto, etc.
Cada una de esas características pueden ser editadas desde el código y su modificación repercute
directamente sobre el valor de los atributos de la clase en la que están basados, pero en el diseñador, la
cosa es más simple. Son campos que podemos modificar y si la propiedad está asociada a algo gráfico, los
cambios los podemos observar al instante. Por ejemplo, intente arrastrar un campo de texto (Line Edit) a
su ventana (en adelante, formulario), y cambie su propiedad “text” a un texto que usted desee. Al
abandonar la edición, notará que los cambios son aplicados inmediatamente.

5.1. Mostrar una ventana desde Python


Luego de que hayamos diseñado nuestra ventana, debemos escribir el código Python necesario para
mostrarla. A continuación, veremos un código incipiente utilizado para alcanzar este fin. Para que éste
funcione, creamos una ventana nueva con Qt Designer y la guardaremos en la misma carpeta que el
archivo .py que contiene el código que la mostrará. El nombre dado al archivo .ui (Extensión de Qt
Designer), es “VentanaPrincipal.ui”.

Nota: Recuerde guardar el archivo .ui, antes de ejecutar el código Python, para que las últimas
modificaciones puedan ser ejecutadas también.

Ejemplo 12: Mostrar una ventana desde Python


import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5 import uic

class Ventana(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("EjemploVentana.ui", self)

aplicacion = QApplication(sys.argv)
nueva_ventana = Ventana()
nueva_ventana.show()
sys.exit(aplicacion.exec())

Puede que, a simple vista, parezca algo confuso, pero luego de la explicación del código, todo quedará
mucho más claro.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 18
CENEAC - Programación con Python Nivel 2.

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5 import uic
Primero incluimos en nuestro módulo, todos los otros módulos necesarios. sys contiene muchos métodos
útiles de la instancia que está corriendo. Como, por ejemplo, el método exit, que nos permite devolver un
valor al intérprete. Esto realmente no es necesario, pero es una buena costumbre. Del módulo QtWidgets,
necesitamos QApplication y QMainWindow. La primera es una clase que inicia, mantiene y gestiona una
instancia de una aplicación Qt, mientras que la segunda es una clase diseñada para representar una
ventana.
Como tercer import, uic, nos permite cargar archivos .ui a nuestro código Python.
class Ventana(QMainWindow):
Creamos una clase que herede de QMainWindow. Esto es una ventana personalizada, que contiene todos
los métodos y atributos de QMainWindow, pero con controles y métodos adicionales.
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("EjemploVentana.ui", self)
En el constructor de esta clase hija, tendremos dos sentencias. La primera llama explícitamente al
constructor de la clase base. Esto es para inicializar correctamente el objeto QMainWindow, que exige
obligatoriamente, una instancia de una clase como parámetro. Luego llamamos a loadUI. Este método se
encarga de cargar un archivo .ui y declarar en el código tantas variables como controles tengamos en el
formulario. En tal sentido, si en Qt Designer, colocamos un campo te texto y lo llamamos “txtTexto”,
tendremos una variable llamada “txtTexto” en nuestro código Python y sus métodos y atributos
disponibles, serán los de la clase correspondiente. Más adelante veremos esto a fondo.
aplicacion = QApplication(sys.argv)
Creamos una nueva aplicación Qt
nueva_ventana = Ventana()
Creamos una nueva ventana
nueva_ventana.show()
Mostramos la ventana creada
sys.exit(aplicacion.exec())
Lanzamos la aplicación, y con ella, el gestor de eventos para nuestra ventana. Mostrar la ventana no basta.
Ella necesita un hilo de ejecución encargado de procesar sus eventos y para ello, es el método exec().
Dependiendo del diseño dado a nuestro formulario en el diseñador, la ventana que se mostrará en pantalla,
es parecida a esta:

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 19
CENEAC - Programación con Python Nivel 2.

Figura 8. Ventana en ejecución

Nota: PyCharm ejecuta esta ventana de una forma limpia. Pero cuando ejecutamos el módulo desde el
explorador, aparece una ventana de comandos, junto a la ventana. Esto es porque, aunque el módulo
cargue una GUI, el programa aún es compatible con la línea de comandos. Para evitar esto, cambie la
extensión del archivo .py a .pyw y ya puede ejecutarlo sin una consola asociada.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 20
CENEAC - Programación con Python Nivel 2.

5.2. QMainWindow
Como dijimos en líneas anteriores, QMainWindow es la clase encargada de representar una ventana en Qt.
Crear una clase hija de ella, nos permite modificar esta ventana por defecto y adaptarla a nuestras propias
necesidades. QtMainWindow actúa como un contenedor de objetos. Esto implica que puede tener otros
controles adentro. Hay varios tipos de contenedores en Qt y el primero que veamos será este, por ser
indispensable en el desarrollo de una GUI. Veamos algunas de sus propiedades (Visibles en Qt Designer).
PROPIEDAD DESCRIPCIÓN
objectName Especifica el nombre del objeto. Este nombre será el que se
mostrará en el inspector de objetos y será el nombre que tendrá la
variable con la que se acceda a él.
windowModality Permite colocar la ventana en modo modal. Esto aplica solo para
aplicaciones que tengan múltiples formularios visibles a la vez.
Cuando un formulario se crea sobre otro y éste tiene
windowModal o applicationModal en esta propiedad, la ventana
que llamó a la nueva, no podrá ser utilizada hasta que esta última
sea cerrada.
enabled Si esta propiedad es True, el formulario podrá utilizarse
normalmente. Si no está marcada, no se podrá operar sobre el
formulario, ni sobre sus controles. No se podrá cambiar de
tamaño, ni mover, maximizar o minimizar. El formulario
permanece visible, pero inactivo.
geometry Permite cambiar el alto y ancho de la ventana en píxeles. También
permite ajustar la posición, pero en la vista de diseño, solo el alto
y ancho.
mínimumSize, maximumSize Ajustan cuál será el tamaño mínimo y máximo del formulario en
pixeles respectivamente. Cualquier tamaño menor al mínimo o
mayor al máximo, no es permitido.
font Permite elegir la el nombre, estilo y tamaño de la fuente que se
usará en el control

cursor Acá se puede seleccionar cuál será el cursor que se mostrarla


cuando se pase el puntero del mouse por encima del formulario

windowTitle El texto que tendrá la ventana en la barra de título

windowOpacity Ajusta la opacidad del formulario, siendo 0, transparente al 100%


y 1, completamente opaco

Nota: Cambiar cualquiera de estas propiedades, o de las otras no mencionadas, repercute directamente
en el comportamiento de la ventana cuando ésta sea ejecutada. Si cambió una propiedad en plan de
prueba, y no recuerda el valor que ésta tenía por defecto, no se preocupe. Cada propiedad tiene un
pequeño botón con una flecha roja en la parte derecha, que permite devolver la propiedad a sus valores
por defecto.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 21
CENEAC - Programación con Python Nivel 2.

5.3. Botones: Command Link Button, Push Button, Tool Button

Figura 9. Ejemplo de botones

Los botones son controles que le permiten al usuario, generar una acción cuando son pulsados. Hay varios
tipos de botones, los primeros tres que veremos, son los mencionados. En teoría, los tres son iguales en
funcionamiento; es decir, se pulsan y se genera un evento que será procesado y se tomará una acción
determinada. La diferencia con el primero (Command Link) es su apariencia, un poco más estilizada que
la del resto. El segundo (Push Button) es un botón corriente, y el tercero (Tool Button) está diseñado para
mostrar diálogos cuando se pulsa, aunque nada le impide comportarse como un Push Button. El control a
elegir en la mayoría de los casos, es un Push Button, pues es el indicado para la mayoría de las tareas.
Los botones, solo por ser objetos gráficos de QT, heredan muchas de las propiedades que ya hemos
descrito en QMainWindow, así que las que se repitan, no se colocarán nuevamente.

PROPIEDAD DESCRIPCIÓN
text Texto del botón

shortcut Combinación de teclas, que, al ser usada, presiona el botón

checkable Si esta propiedad es seleccionada, el botón podrá tener dos estados:


seleccionado y deseleccionado. Pulse para seleccionar, pulse de
nuevo para deseleccionar.
checked Si la propiedad checkable está activada, esta propiedad indicará si
el botón estará seleccionado por defecto, o no.

default (Solo Push y Cuando esta propiedad sea verdadera, el botón tendrá un aura azul,
Command Link) que indica que es el botón por defecto (Ver fig. 9). Cuando esto
suceda, al presionar ENTER, se pulsará el botón cambién. Es para
crear botones por defecto, y solo puede haber uno por formulario.

flat (Solo Push) Le da una apariencia plana y sin bordes al botón.

arrowType (Solo Tool Coloca una flecha en lugar de un texto, en el botón.


Button)

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 22
CENEAC - Programación con Python Nivel 2.

Nota: Los colores del texto en los distintos controles se pueden cambiar ajustando los colores de la
propiedad Palette. Por defecto todos los controles comparten la paleta de colores del formulario al que
pertenecen. En tal sentido, al cambiar los colores del formulario, también se cambiarán los colores de
sus controles. Para tener colores distintos en cada control, modifique la paleta de colores de los mismos.
Pues éstos tienen precedencia sobre los del formulario.

Figura 10. Ejemplo de controles Radio Button, Check Box y Button Group

5.4. Check Box y Radio Button y Group Box


Son controles diseñados para solicitar una respuesta del usuario en forma de selección simple (Radio
Button) o selección múltiple (Check Box). Cuando un Radio Button está seleccionado, ningún otro Radio
Button en el mismo contenedor puede estar seleccionado, y de estarlo, se deselecciona automáticamente.
Por su parte, un Check Box, puede estar seleccionado al mismo tiempo que otro, pues su uso es para
selección múltiple.
En el caso de los Radio Button, su uso es idéntico al de los botones vistos anteriormente, su propiedad
checked, permite seleccionarlo por defecto. En el caso de los Check Box, es casi lo mismo, con la
salvedad de que tienen una propiedad llamada tristate. Esta propiedad es booleana y si es puesta en
True (seleccionada), el Check Box en cuestión, puede tener tres estados: seleccionado, deseleccionado y
marcado (Ver fig. 10).
Los Button Groups, son controles que pueden tener otros controles adentro. A este tipo de controles se les
denomina contenedores. Si colocamos varios controles radio Button en un formulario, solo uno podrá
estar seleccionado, pero si los colocamos adentro de un Button Group, y dejamos otros dos sueltos en el
formulario, solo uno de los Radio Button puede estar seleccionado en el formulario y a su vez, solo uno
podrá estar seleccionado en el Button Group. Este comportamiento es atribuible al hecho de que un Button
Group agrupa los controles de selección simple y los aísla del resto. Un uso práctico del Button Group,
aparte de dar un toque estético y un título para el grupo de botones, es precisamente agrupar controles
Radio Button.
Note también el uso de un Button Group para los Check Box que están debajo. El Button Group no les
afecta; solo se usa con fines estéticos y para ayudar a la creación de una interfaz intuitiva.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 23
CENEAC - Programación con Python Nivel 2.

Nota: Si marca la casilla checked de un Radio Button, y la desmarca luego, la selección del control no
desaparecerá. Esto es porque una vez que se selecciona un Radio Button, ya no es posible
deseleccionarlo, a menos que se seleccione otro. Tenga eso en cuenta al momento de diseñar su
aplicación.

Figura 11. Ejemplo de Plain Text Edit, Text Edit y Line Edit

5.5. Line Edit, Text Edit, Plain Text Edit


Son controles utilizados para recibir datos del usuario, al igual que los controles anteriores, solo que esta
información puede ser personalizada, y dependiendo de nuestros requerimientos, ésta puede limitarse solo
a una línea (Line Edit), a varias líneas en texto plano (Plain Text Edit) o a varias líneas con texto
enriquecido, o con formato (Text Edit). Puede que siempre nos sintamos atraídos a usar un Text Edit. Sin
embargo, esto no siempre es recomendable. Estos controles son más lentos y gastan más memoria que los
de texto plano, así que es bueno usarlos, solo cuando la situación lo amerite.
A continuación, una lista de las nuevas propiedades que debemos tener en cuenta con estos tres controles:
PROPIEDAD DESCRIPCIÓN
text (Solo Line Edit) Especifica el texto del control
maxLength (Solo Line Edit) Indica la cantidad máxima de caracteres a ingresar en el
control
echoMode (Solo Line Edit) Indica los caracteres que aparecerán al escribir en el
control. Esto es útil para almacenar contraseñas y otros
datos sensibles.
 NoEcho: No muestra nada en el control
 Password: Muestra puntos negros en lugar del
texto
 Normal: Muestra el texto normal, sin esconder
caracteres
 PasswordEchoOnEdit: Muestra el texto normal
al escribir, y cuando se posiciona el foco sobre
otro control, se esconde el texto con puntos

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 24
CENEAC - Programación con Python Nivel 2.

negros.

alignment (Solo Line Edit) Especifica si el texto estará centrado, hacia la derecha o
hacia la izquierda, tanto vertical como horizontal.

readOnly Indica si se puede editar el texto del control

clearButtonEnabled (Solo Line Edit) Si se coloca en True, aparecerá un pequeño botón con
una “X” en la parte derecha del control. Si se pulsa, se
vacía el texto.

undoRedoEnabled (Solo Plain Text Edit Si esta propiedad es verdadera, se habilita el uso de
y Text Edit) Ctrl+Z y Ctrl+Shift+Z para deshacer y rehacer los
cambios realizados respectivamente.

lineWrapMode (Solo Plain Text Edit y Indica el comportamiento del texto cuando una línea de
Text Edit) éste es más larga que el ancho del control.
 NoWrap: No sucede nada con el texto. Si las
barras horizontales están activas, se puede
acceder al texto oculto, desplazándolas.
 WidgetWidht: Se ajusta el texto al ancho del
control.

plainText (Solo Plain Text Edit) Cambia el texto del control.

verticalScrollBarPolicy, Modifica la visibilidad de las barras de desplazamiento.


horizontalScrollBarPolicy  ScrollBarAsNeeded: Solo se muestran cuando
(Solo Plain Text Edit y Text Edit) son necesitadas, es decir, cuando haya un texto
oculto al que se pueda acceder.
 ScrollBarAlwaysOn: Siempre se mostrarán.
 ScrollBarAlwaysOff: Nunca se mostrarán.

tabChangesFocus (Solo Plain Text Edit Una propiedad interesante. Cuando se pulsa el botón
y Text Edit) Tab, por defecto se muestra una tabulación en el campo
de texto. Pero si esta propiedad está activa, al presionar
Tab, se cambia el foco del control al siguiente, tal cual
como si de otro control se tratase.

html (Solo Plain Text Edit y Text Edit) Indica el texto que tendrá el control. Este texto debe
estar en formato HTML si se quieren efectos.
acceptRichText (Solo Text Edit) Si es verdadero, se puede colocar texto enriquecido (con
formato) en el control, si es falso, no.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 25
CENEAC - Programación con Python Nivel 2.

5.6. Etiquetas (Label)

Figura 12. Ejemplo de etiquetas en una ventana

Son controles elementales, pero indispensables para mostrar cualquier información en la ventana. Todo
texto mostrado en un Label será estático en un principio, es decir, no se podrá modificar, a no ser que
rompiendo con la esencia de un Label, el programador decida que el mismo pueda editarse.
Un Label no tiene muchas propiedades nuevas, pero tiene una en específico (textInteractionFlags) que
contiene a su vez, otras propiedades muy interesantes relativas a la forma en la que se comporta el texto de
la etiqueta con respecto al usuario, veamos las más relevantes de ellas:
PROPIEDAD DESCRIPCIÓN
TextSelectableByMouse Si está marcada, el texto del Label puede ser seleccionado
por el mouse.

TextSelectableByMouse Si está marcada, el texto del Label puede ser seleccionado


por el teclado
TextEditable Si esta propiedad está activada, el texto del Label puede ser
editado
NoTextInteraction (por defecto) No se puede editar el texto, ni seleccionarlo de ningún
modo por el usuario

5.7. List Widget

Figura 13. Ejemplo de List Widget

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 26
CENEAC - Programación con Python Nivel 2.

Un List Widget es un control que contiene una lista de ítems que el usuario puede seleccionar. Si la lista
de ítems es más larga que la cantidad de filas admitidas por el control, es usual que éste tenga una barra de
desplazamiento que nos permita visualizar los ítems restantes.
Estos controles son útiles para mostrar resultados de consultas en las que el usuario deba elegir una o más
opciones. Acá algunas de sus propiedades:
PROPIEDAD DESCRIPCIÓN
tabKeyNavigation Si esta propiedad está activa, al pulsar Tab, se cambiará al siguiente ítem
seleccionado y no al siguiente control (por defecto)
showDropIndicator Si esta propiedad está activada (por defecto), se pueden arrastrar ítems de
un lugar de la lista a otro lugar de la misma lista, u otro control
compatible.
alternatingRowColors Intercambia los colores de fondo de los ítems de la lista, tal cual como en
esta tabla.
selectionMode Configura la forma en la que los ítems pueden ser seleccionados:
 NoSelection: No se puede seleccionar ningún ítem
 SingleSelection: Solo se puede seleccionar un ítem.
 MultiSelection: Se pueden seleccionar varios ítems. Si se selecciona
un ítem al inicio de la lista y se suelta el botón izquierdo del mouse y
luego se presiona sobre otro elemento, éste se seleccionará y los que
estaban seleccionados al inicio, se deseleccionan. Arrastrando el
puntero del mouse sobre los ítems, seleccionará varios.
 ExtendedSelection: Igual que MultiSelection, salvo que una nueva
selección, no borra la anterior. Se pueden seleccionar todos los ítems
en cualquier orden.
 ContinuousSelection: Al seleccionar un elemento, y luego
seleccionar otro, se seleccionan también, todos los ítems que haya
entre el primero y el segundo seleccionado. Esto garantiza siempre
una selección contigua.
sortingEnabled Los ítems se ordenarán a medida de que se vaya cambiando el contenido
del List Widget
viewMode Indica la vista de la lista, si se deja por defecto, queda como en la figura
14, sino, se organiza por íconos (en caso de que le hayamos cargado
algunos)
currentRow Indica el ítem que estará seleccionado por defecto

Nota: No hemos visto cómo agregar ítems a los controles List Widget. Esto es porque esta operación se
realiza en tiempo de ejecución, a través de código Python, que será tratado en el siguiente tema.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 27
CENEAC - Programación con Python Nivel 2.

5.8. Combo Box

Figura 14. Ejemplo de Combo Box

Es otro de los controles ampliamente utilizados. El Combo Box, o lista desplegable, es similar a un List
Widget, solo que admite una única opción y en un principio está plegada. Estos controles son útiles en
aquellas situaciones en las que necesitemos una opción del usuario y tengamos poco espacio para colocar
una lista. Incluso con un espacio amplio, un Combo Box suele ser la opción más estilizada posible.
Estas son algunas de sus propiedades:
PROPIEDAD DESCRIPCIÓN
editable Si está activada, esta propiedad permite escribir sobre el Combo Box
como si fuera una línea de texto.

currentText Establece el texto del control por defecto.

maxVisibleItems Indica la cantidad máxima de ítems que se verán al desplegar la lista. Si


la cantidad de Items visibles es menor que la cantidad total de ítems,
aparecerá una barra de desplazamiento.
maxCount Cantidad máxima de ítems en el control.

insertPolicy Indica en qué parte se insertarán los nuevos elementos:


 NoInsert: No agregará nuevos ítems.
 InsertAtTop: Los agregará al inicio de la lista.
 InsertAtCurrent: Los insertará en la posición de la selección
actual.
 InsertAtBottom: Colocará el nuevo ítem de último.
 InsertAfterCurrent: Insertará el ítem luego de la selección
actual.
 InsertBeforeCurrent: Insertará el ítem antes de la selección
actual.
 InsertAlphabetically: Insertará los ítems en orden alfabético.

duplicatesEnabled Si esta propiedad está activa, se podrán colocar ítems con valores
idénticos en el control.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 28
CENEAC - Programación con Python Nivel 2.

Notas: Este fue un paseo por algunos de los controles más utilizados en el desarrollo de una GUI. Al igual
que con el List Widget, tampoco se ilustra por los momentos, la manera de agregar nuevos ítems en el
Combo Box.
Se le sugiere al lector, probar el resto de los controles, que no son pocos. Si necesita una orientación
acerca del uso de ellos, o de cualquier clase de PyQT, siéntase en la libertad de consultar la
documentación en línea de PyQT (en inglés):
http://pyqt.sourceforge.net/Docs/PyQt5/
o un curso muy completo de PyQT5, también en inglés:
https://programmica.com/builds/pyqt5-tutorial/pdf/PyQt5Tutorial.pdf

Tenga en cuenta una cosa. Nosotros (aquellas personas dedicadas a la redacción de material académico
de calidad, relativo a la programación y temas afines), nos damos a la tarea de poner a su disposición,
manuales como este que, si bien intentan abarcar todo un curso de creación de GUI y Bases de datos, no
tienen ánimos de cubrir las más de 300 clases de PyQT, por lo que la documentación oficial, siempre será
un referente para cualquier inquietud. La inmensa mayoría de la documentación de este y otros
lenguajes, así como las bibliotecas compatibles con ellos, está en idioma inglés, por lo que es aconsejable
su dominio, al menos a un nivel técnico.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 29
CENEAC - Programación con Python Nivel 2.

6. MÉTODOS Y EVENTOS DE PYQT5


6.1. Toma de contacto con la gestión de eventos
Esta es la parte de la guía en la que aprenderá el código que debe escribir para interactuar con esa interfaz
que se dedicó a crear con Qt Designer. Acá convergen muchos paradigmas, muchas maneras distintas de
hacer las cosas y todas trabajan en conjunto para lograr un acabado impecable en nuestra aplicación.
Necesitaremos tener en cuenta que trabajaremos con la programación orientada a objetos, programación
orientada a eventos y programación gráfica.
PyQT pone a nuestra disposición muchísimas clases y ya hemos analizado varias de ellas. La que
sobresale es QMainWindow. Como mencionamos, es la encargada de procesar todos aquellos datos
asociados a una ventana en específico. Pero de nada nos sirve una ventana que solo muestre un dato.
Nuestra audacia nos permite notar que, si colocamos botones en un formulario, nada sucede al pulsarlos.
Si colocamos un List Widget, nada sucede al seleccionar un ítem.
Cada acción que realizamos en un formulario, o en uno de sus controles, se denomina evento. Cada vez
que pulsamos un botón, o pasamos el puntero del mouse sobre un label, o seleccionamos un ítem de un
Combo Box, se genera un evento distinto. Nuestro programa debe responder a cada uno de los eventos que
le interese manejar.
Coloquemos un ejemplo práctico, tenemos un formulario con un botón. Queremos que el programa se
cierre al pulsar el botón. Para ello necesitamos hacernos dos preguntas:
- ¿Qué queremos que suceda?
- ¿Cuándo queremos que suceda?
La respuesta a la primera pregunta es lógica: Cerrar el programa. ¿Cuándo? Cuando se pulse el botón. Allí
tenemos todo lo que necesitamos. Tenemos que intervenir el evento en el que se pulsa el botón y en
respuesta a dicho evento, cerrar el programa.
Los eventos se atienden con métodos, es decir, por cada evento que deseemos intervenir, debemos crear
un método en la clase de la ventana que se encargue de procesar todas aquellas acciones que queremos
realizar como respuesta a ese evento. Nuestra ventana sería así:

Figura 15. Formulario para probar eventos

En el inspector de objetos, le colocaremos un nombre al botón. Éste será: “btn_salir”.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 30
CENEAC - Programación con Python Nivel 2.

Figura 16. Cambio de nombre del botón de salida

Luego guardamos el archivo en el mismo directorio de nuestro archivo .pyw y ejecutamos el mismo
código que vimos antes, pero con algunas modificaciones, el nombre del archivo usado en esta guía para
este ejemplo es PruebaEvento.ui.
Ejemplo 13: Respuesta a eventos
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QEvent
from PyQt5 import uic

class Ventana(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("PruebaEvento.ui", self)
for i,j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)

def eventFilter(self, control, evento):


if evento.type() == QEvent.MouseButtonPress and control == self.btn_salir:
sys.exit(0)
return QWidget.eventFilter(self, control, evento)

if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = Ventana()
mi_ventana.show()
sys.exit(app.exec())

Bien, el código nuevo puede ser un poco confuso para aquellos que recién inician con la programación
orientada a eventos, pero antes de que el pánico nos invada, expliquemos cada parte del ejemplo anterior.

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QEvent
from PyQt5 import uic

Acá gestionamos las importaciones a nuestro módulo principal. Necesitamos a sys, para operar sobre los
argumentos de nuestro programa, los métodos de salida, etc. QtWidgets contiene las clases de los
controles de Qt. Muy útil. De QtCore tomaremos QEvent, que contiene una lista de enteros
correspondientes a cada uno de los eventos soportados por Qt. Y uic, para cargar la GUI.
class Ventana(QMainWindow):
def __init__(self):

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 31
CENEAC - Programación con Python Nivel 2.

QMainWindow.__init__(self)
uic.loadUi("PruebaEvento.ui", self)
Hasta aquí el código del constructor del Widget central, queda igual que el ejemplo que vimos con
anterioridad. Se llama al constructor de la clase base (QMainWindow) y luego cargamos la interfaz
gráfica desde un archivo. La llamada a loadUI también declara todas las variables locales necesarias para
operar sobre los controles que declaramos en Qt Designer.
for i,j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)

Un código muy importante. En PyQT tenemos tres manera de manejar eventos:


1. Con eventos por defecto: Cada control tiene un evento por defecto, los botones tienen el clicked,
los Line Edit tienen el Enter, y así sucesivamente. Podemos asignarle acciones a cada uno de esos
eventos con el método connect(), y solo esos eventos por defecto estarán disponibles. La ventaja
es que el código se entiende más y es más corto, la desventaja es hay pocos eventos para elegir.
2. Creando una clase hija de cada control, modificarla y agregar manualmente un objeto de cada
clase a nuestro formulario, todo a puro código. La ventaja de esta forma es que solo tenemos que
procesar eventos específicos y en cierto grado, puede aumentar el rendimiento de nuestra
aplicación. La desventaja es que implica la creación de una clase diferente por cada control nuevo.
Algo engorroso y que genera al final, un código innecesariamente largo.
3. Con un filtro de eventos: Esto combina las ventajas de las dos formas anteriores. Podemos
manejar todos los eventos que queramos con una sola clase para todos sus controles. Este es el
método que usaremos. La desventaja es que el código puede ser un poco complicado, pero luego
de que nos acostumbremos, será muy sencillo.
Para poder capturar todos los eventos de un control, es necesario instalar un filtro de eventos en cada uno.
Esto se puede hacer de la siguiente forma:
self. installEventFilter(self)
control1.installEventFilter(self)
control2.installEventFilter(self)
controln.installEventFilter(self)
Como es tedioso tener que colocar una línea de esas por cada control y sin contar que podemos olvidarnos
de agregarla luego de colocar un control nuevo, es idóneo hacerlo automáticamente. El ciclo for que
aparece en el código, itera sobre un diccionario devuelto por vars. Este método devuelve una lista de
variables locales de un objeto. El objeto es self. Es decir, la instancia actual de la clase Ventana. El
diccionario devuelto contendrá al propio self, a btn_salir y a todo aquel control que hay en el formulario.
El método isinstance nos dice si el tipo de un objeto es igual a una clase específica o a una de sus clases
base. Como todos los controles heredan de QWidget, es esta la clase que pasaremos como segundo
parámetro a isinstance para comprobar si ésta coincide con el objeto suministrado como primer parámetro.
Si coincide, entonces llamamos a su método installEventFilter para instalar un filtro de eventos para ese
control.

Nota: Instalar un filtro de eventos solo para los controles que lo usarán, puede tener una ventaja de
rendimiento; sobre todo cuando la cantidad de controles es grande y no necesitamos manejar los
eventos de todos ellos. Si usa una gran cantidad de controles, quizás deba considerar añadir filtros para
ellos, uno por uno y solo para aquellos que lo requieran.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 32
CENEAC - Programación con Python Nivel 2.

def eventFilter(self, control, evento):


if evento.type() == QEvent.MouseButtonPress and control == self.btn_salir:
sys.exit(0)
return QWidget.eventFilter(self, control, evento)
Este es el procedimiento encargado de manejar los eventos de la ventana y sus controles. Es un
procedimiento presente en las clases bases de Ventana, y al escribirlo acá, será sobrescrito. Este método se
llamará automáticamente cada vez que ocurra un evento en los controles que tengan un filtro instalado, así
que debemos comparar si cada evento entrante coincide con un tipo y un control específico.
Comparamos si el tipo del evento es MouseButtonPress, y si el dueño de este evento es btn_salir. Si
ambas condiciones son verdaderas, entonces se llama al método exit() de sys. Esto termina la ejecución
del programa apenas se haga clic en el botón. No nos olvidemos de escribir en el return, la llamada al
eventFilter de la clase base, para que el evento sea procesado correctamente.
if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = Ventana()
mi_ventana.show()
sys.exit(app.exec())
Las últimas líneas son casi idénticas al ejemplo número 6, pero subordinadas al cumplimiento de un if.
Cuando un módulo Python se ejecuta, corre todo aquel código suelto que haya en el mismo. Cuando el
módulo es el principal (aquel que se ejecutó de primero por el intérprete de Python), la variable
predefinida __name__ tendrá el valor de “__main__”, mientras que, si no es el principal, tendrá su propio
nombre. Algo útil para que éste código solo se ejecute cuando este módulo sea el principal, y se pase por
alto cuando no lo sea.

Nota: Cuando el código de respuesta a un evento, sea mayor a 5 líneas de código, es recomendable,
colocarlo en un método de la clase y llamarlo desde el filtro de eventos. Esto es para evitar el código
spaghetti y ordenar mejor nuestro proyecto, por lo que se sugiere que, desde la etapa de planificación,
se tenga esto en mente: no contaminar el gestor de eventos y colocar allí, solo el mínimo código
necesario para que todo funcione.

6.2. Eventos de PyQt


Acá una lista de los eventos más usados que son soportados por Qt en su clase QEvent. Algunos de los
eventos pueden tener métodos asociados. Para usarlos, escriba el nombre del parámetro que contiene el
evento (en el ejemplo es “evento”), seguido de un punto, el nombre del método y luego su pase de
parámetros. Para una lista completa de los eventos de QEvent, visite la documentación oficial (en inglés):
http://pyqt.sourceforge.net/Docs/PyQt4/qevent.html
EVENTO DESCRIPCIÓN
FocusIn Es generado cada vez que un control recibe el foco. El foco puede verse
como el punto de atención del sistema operativo entero sobre un único
control. Cuando hacemos clic en un campo de texto, el borde de éste
cambia de color y aparece un cursor parpadeante. Esto quiere decir que,
por los momentos, este control tiene el foco. Cuando hacemos clic en un
botón, el borde cambia y si pulsamos enter, se lanzará su evento clicked.

FocusLost Es generado cuando un control pierde el foco. Esto sucede cuando otro
control lo toma.
Close Aplica para ventanas. Se genera cuando éstas se cierran.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 33
CENEAC - Programación con Python Nivel 2.

Hide También aplica para ventanas. Cuando ésta se minimiza, o se oculta por
código, se lanza este evento.
HoverEnter Se genera cuando el puntero del mouse entra en el área visible del
control.
Métodos:
 pos(): Devuelve un objeto QPoint que contiene las coordenadas
X e Y, correspondientes a la posición exacta del puntero del
mouse con respecto al control. Para acceder a las coordenadas
del QPoint, puede escribir:
x = evento.pos().x()
y = evento.pos().y()

HoverMove Se genera cuando se mueve el cursor por encima de un control. El


evento HoverMove también tiene un método pos() idéntico al de
HoverEnter.
HoverLeave Se genera cuando el cursor sale del área del control. Este evento también
tiene un método pos(), pero las coordenadas del QPoint que devuelve,
serán siempre -1 para x e y.

KeyPress Se genera cuando se pulsa una tecla en un control. Teclas temporales


(tildes romances, acentos circunflejos, etc.) no son capturadas hasta que
se pulse la tecla esperada. Ejemplo: al pulsar la tecla de tilde, no se
genera un evento KeyPress, cuando se pulsa una vocal luego de la tilde,
se acentúa la vocal y se llama a KeyPress con la vocal acentuada como
tecla.

Teclas especiales (Ctrl, Alt, Alt Gr, teclas de función, etc) generan
eventos KeyPress. Cuando se pulsa una combinación de ellas, se genera
un evento KeyPress por cada nueva tecla presionada. En tal sentido,
Ctrl+Alt+A, genera tres eventos KeyPress.

Métodos:
 key(): Tecla que fue pulsada. Este método devuelve un entero
que será igual a cualquiera de las constantes definidas en la clase
Qt (Módulo QtCore) que inicien con Key_.
 text(): El texto introducido en el evento. Si es un caracter
imprimible y visible (Letras, símbolos o números), este método
lo devolverá. Si es un caracter imprimible pero no visible (saltos
de línea, backspaces, retornos de carro, etc), el método lo
devuelve, pero tenga cuidado si su plan es concatenarlos, pues el
resultado puede no ser el esperado. Si es una tecla no
imprimible, devuelve una cadena vacía.
 modifiers(), indica si un modificador está pulsado al mismo
tiempo que la tecla del evento (que también puede ser un
modificador). Para ello puede hacer uso de las constantes
definidas en la clase Qt:
o ShiftModifier (Tecla Shift)
o ControlModifier (Tecla Ctrl)
o AltModifier (Tecla Alt)
o MetaModifier (Tecla Meta, o Windows®)

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 34
CENEAC - Programación con Python Nivel 2.

o NoModifier (Ningún modificador activo)


Puede usar cualquier combinación (salvo NoModifier), siempre
y cuando las separe con un or binario (Barra vertical):

if evento.modifiers() == Qt.ShiftModifier | Qt.AltModifier:


print("Presionado Shift + Alt")

KeyRelease Se genera cuando una tecla fue soltada. Los métodos de este evento son
iguales a los de KeyPress.

MouseButtonPress Se presionó un botón del ratón en el control.


Métodos:
 button(): Devuelve el botón que generó el evento. Será una de
las siguientes constantes definidas en la clase Qt:
o LeftButton: Botón izquierdo
o RightButton: Botón derecho
o MidButton: Botón central
 buttons(): Devuelve el estado de los botones del mouse. Será
una combinación de los botones listados arriba, y al igual que
con los modificadores de teclas, podemos comparar varios
botones a la vez, con un or binario.
 pos(): Devuelve un QPoint con las coordenadas locales
(relativas al control) en las que se generó el evento. Recuerde
que puede acceder a las coordenadas por individual, si llama a
x() o y().
 windowPos(): Devuelve un QPoint con las coordenadas
(relativas a la ventana) en las que se generó el evento.
 screenPos(): Devuelve un QPoint con las coordenadas (relativas
a la pantalla) en las que se generó el evento.
 x(): Devuelve la coordenada X del lugar en el que se generó el
evento, con respecto al control.
 y() Devuelve la coordenada Y del lugar en el que se generó el
evento, con respecto al control.

MouseButtonRelease Se genera cuando se suelta el botón del mouse. Los métodos de este
evento son iguales a los del evento MouseButtonPress.

MouseButtonDblClick Se genera cuando se hace doble clic en un control. Los métodos de este
evento son iguales a los del evento MouseButtonPress.

MouseMove Parecido a HoverMove. Este evento se genera cuando se mueve el cursor


del mouse sobre un control. Su diferencia con HoverMove radica en la
propiedad booleana mouseTracking del control que recibe el evento. Si
esta propiedad es verdadera, MouseMove funciona igual que
HoverMove. Si la propiedad es falsa, este evento solo se genera cuando
hay algún botón del mouse pulsado mientras se arrastra el cursor sobre el
control.

Move Se genera cuando cambia la posición de un control. Casi siempre es

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 35
CENEAC - Programación con Python Nivel 2.

usado para el QMainWindow pero funciona para cualquier control.


Métodos:
 pos(): Devuelve un QPoint con la nueva posición del control.
 oldPos(): Devuelve un QPont con la antigua posición del
control.

Paint Se genera cuando una porción de la ventana necesita ser repintada. Esto
puede pasar por varios motivos (se muestra la ventana, se oculta un
menú, se mueve un control, se mueve la ventana, se mueve una ventana
que está encima de la nuestra… etc.).
Métodos:
 rect(): Devuelve un QRect con la porción de la ventana a ser
repintada. QRect tiene tres métodos que nos pueden ayudar a
saber la posición exacta:
o x(): Coordenada X de la esquina superior izquierda de la
región.
o y(): Coordenada Y de la esquina superior izquierda de la
región.
o widht(): Ancho de la región.
o height(): Alto de la región.

Se genera cuando se cambia el tamaño de la ventana.


Resize Métodos:
 size(): Devuelve el nuevo tamaño de la ventana en un objeto de
tipo QSize. Este objeto tiene dos métodos muy útiles:
o width(): Ancho
o height(): Alto
 oldSize(): Devuelve el antiguo tamaño de la ventana en un
objeto de tipo QSize().

Show Se genera cuando se muestra un control, o una ventana.

Wheel Se genera cuando se acciona la rueda del ratón (no el botón central)
hacia arriba o hacia abajo. El evento comparte los métodos de
MouseButtonPress.
Métodos:
 delta(): Este método devuelve un entero que será positivo si se
desplazó la rueda hacia arriba, o un valor negativo si se
desplazó hacia abajo.

Nota: En la parte final de esta guía aparecen abundantes ejemplos acerca del uso de eventos.

6.3. Métodos de PyQt


Hasta ahora hemos visto cómo utilizar eventos en PyQt, pero necesitamos saber cómo responder a ellos;
es decir, tomar las acciones necesarias cuando se genere un evento: mostrar una ventana, cambiar el texto
de un Label, o el de un botón, mostrar un mensaje en pantalla, cambiar los ítems de una lista o de un
Combo Box. Qt Framework nos provee cientos de clases y cada una de ellas tiene varios métodos. Éstos
son los que se encargan de hacer todas las acciones descritas en este párrafo y muchas más.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 36
CENEAC - Programación con Python Nivel 2.

A continuación, una lista de los métodos más utilizados para los controles que hemos visto. Estos métodos
están disponibles para objetos de tipos específicos y tipos derivados de éstos. Por ejemplo, un método que
esté disponible para un control QMainWindow, también lo estará para todas aquellas clases creadas como
hijas de QMainWindow. QWidget engloba todos los controles (Ventanas incluidas), etc.
MÉTODO CLASES DESCRIPCIÓN Y USO
setTitle(titulo) QMainWindow Cambia el título de una ventana. Recibe una
cadena con el nuevo texto, como primer
parámetro.
showMinimized() QMainWindow Minimiza la ventana.
showMaximized() QMainWindow Maximiza la ventana.
showFullScreen() QMainWindow Expande la ventana a pantalla completa.
setNormal() QMainWindow Restaura la ventana a su tamaño original.
show() QMainWindow Muestra la ventana.
hide() QMainWindow Oculta la ventana.
close() QMainWindow Cierra la ventana.
isMinimized() QMainWindow Devuelve true si está minimizada. False en
caso contrario.
isMaximized() QMainWindow Devuelve true si está maximizada. False en
caso contrario.
isFullScreen() QMainWindow Devuelve true si está en pantalla completa.
False en caso contrario.
isHidden() QWidget Devuelve True si está oculto. False en caso
contrario.
isVisible() QWidget Devuelve True si está visible. False en caso
contrario.
hasFocus() QWidget Devuelve true si el control tiene el foco. False
en caso contrario.
height() QWidget Devuelve el alto del control, en píxeles.
width() QWidget Devuelve el ancho del control, en píxeles.
x() QWidget Devuelve la coordenada X, de la esquina
superior izquierda del control.
y() QWidget Devuelve la coordenada Y, de la esquina
superior izquierda del control.
resize(w, h) QWidget Cambia el tamaño del control o ventana. El
primer parámetro es el ancho, el segundo es el
alto.
setMaximumHeigth(n) QWidget Establece la altura máxima de un control.
Cualquier llamada a resize, con un valor de h,
mayor al pasado a esta función, funcionará
como si a dicho parámetro se le hubiera pasado
el valor máximo.
setMaximumWidth(n) QWidget Establece el ancho mínimo de un control Si se
llama a resize con un ancho mayor a este, el
ancho se adapta al máximo.
setMinimumHeight(n) QWidget Establece la altura mínima de un control.
setMinimumWidth(n) QWidget Establece el ancho mínimo de un control.
move(x, y) QWidget Cambia el Widget de posición. Puede recibir
move(pos) dos parámetros enteros (x e y) o un único

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 37
CENEAC - Programación con Python Nivel 2.

parámetro con un QPoint. Recordemos que un


QPoint es una clase con las dos coordenadas.
pos() QWidget Devuelve la posición del control en un QPoint
setEnabled(valor) QWidget Activa o desactiva el control. Si se pasa True,
lo activa, False lo desactiva.
isEnabled() QWidget Indica si el control está activo o no
windowTitle() QWidget Devuelve el texto del título del Widget.
Lógicamente esto solo cobra sentido para
ventanas y diálogos. No para controles adentro
de ellos.
setText(texto) QLabel, QLineEdit, Cambia el texto de un control. El texto debe ser
QCheckBox, una cadena de caracteres pasada en su
QRadioButton, parámetro.
QPushButton,
QToolButton,
QCommandLinkButton,
QListWidgetItem.
Otros controles que
soporten un cambio de
texto plano

text() QLabel, QLineEdit, Devuelve el texto de un control en una cadena


QCheckBox, de caracteres.
QRadioButton,
QPushButton,
QCommandLinkButton,
QListWidgetItem.
Otros controles que
soporten un cambio de
texto plano
setDefault(valor) QPushButton, Indica si el botón que llama al método será el
QCommandLinkButton botón por defecto. Si paso True como
parámetro, el botón será el botón por defecto.
Si paso False, ya el botón no será el botón por
defecto.
isDefault() QPushButton, Devuelve True si el botón que llamó al método
QCommandLinkButton es el botón por defecto. False en caso contrario.
Devuelve el valor de la propiedad default.
setCheckable(valor) Todos los botones Si se le pasa True a este método, el botón podrá
seleccionarse. Si se le pasa False, no podrá
seleccionarse. En el caso de QRadioButton y
QCheckBox, esto es ovbvio. Pero para los
otros tres tipos de botones, esta propiedad en
True, implica que cada vez que se presionen,
cambia su estado.
isCheckable() Todos los botones Indica si el botón actual se puede seleccionar o
no. Devuelve el valor de la propiedad
checkable.
isChecked() Todos los botones Devuelve True si el botón está actualmente
seleccionado. False en caso contrario. Al

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 38
CENEAC - Programación con Python Nivel 2.

lanzarse el evento MouseButtonPress usted


recibirá el botón con el estado nuevo, no el
anterior.
isTristate(valor) QCheckBox Establece la cantidad de estados posibles del
Check Box. Si el parámetro es True, el Check
Box podrá tener tres estados: deseleccionado,
seleccionado y marcado (ver Fig. 10)
setMaxLength(maxim QLineEdit Establece la cantidad máxima de caracteres que
o) puede tener un Line Edit.
getMaxLength() QLineEdit Devuelve la cantidad máxima de caracteres que
puede tener un Line Edit.

Nota: Recuerde que puede obtener la


cantidad de caracteres de un String,
usando la función len()

setEchoMode(modo) QLineEdit Establece la visibilidad de los caracteres


introducidos en el control. Los valores que
puede tener son:
 QLineEdit.NoEcho
 QLineEdit.Password
 QLineEdit.Normal
 QLineEdit.PasswordEchoOnEdit
Para una descripción de cada uno, vea la
propiedad asociada.
setAlignment(valor) QLineEdit Modifica la alineación del texto en el control.
El valor suministrado debe ser una
combinación de dos valores separados por un
or binario (barra vertical). Estos dos valores
deben ser: uno de orientación vertical y otro de
orientación horizontal.
Los de orientación vertical son:
 Qt.AlignTop
 Qt.AlignVCenter
 Qt.AlignBotton

Los de orientación horizontal son:


 Qt.AlignLeft
 Qt.AlignRight
 Qt.AlignHCenter
 Qt.AlignJustify

Para orientar el texto en el centro vertical y a la


izquierda, podemos usar este código:

self.texto.setAlignment(Qt.AlignVCenter |
Qt.AlignLeft)

setReadOnly(editable) Todos los campos de Si se le pasa True, como parámetro, el texto del

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 39
CENEAC - Programación con Python Nivel 2.

texto control no se podrá modificar. Si se le pasa


False, podrá modificarse.
setPlainText(texto) QPlainTextEdit Cambia el texto del control. Recibe una cadena
de caracteres como argumento, con el nuevo
texto.
setHtml QTextEdit Cambia el texto del control. Recibe como
parámetro, una cadena de caracteres en formato
HTML.
toPlainText() QTextEdit Convierte el texto del control a texto plano y lo
regresa.
isSortingEnabled(v) QListWidget Indica si los ítems de la lista estarán ordenados.
Si como parámetro coloca True, se ordenarán.
Si coloca False, se insertarán al final.
setSelectionMode(Sel) QListWidget Indica la forma en la que se seleccionarán los
ítems. El parámetro puede ser cualquiera de los
siguientes:
 QListWidget.NoSelection
 QListWidget.SingleSelection
 QListWidget.MultiSelection
 QListWidget.ExtendedSelection
 QListWidget.ContinuousSelection

Para la explicación de cada uno, consulte la


propiedad asociada.

setCurrentRow(n) QListWidget Cambia la fila seleccionada. Debe ser un


número entre 0 y la cantidad de ítems -1.

currentRow() QListWidget Obtiene en un entero, la fila seleccionada, o -1


si no hay ninguna seleccionada.
addItem(str) QListWidget, Agrega un ítem al control. Recibe un
QComboBox parámetro con el texto del ítem.
addItems(lista) QListWidget, Agrega varios ítems al control. Recibe una lista
QComboBox o tupla de cadenas de caracteres como
parámetro.
count() QListWidget, Devuelve un entero con la cantidad de ítems en
QComboBox el control
insertItem(pos, texto) QListWidget, Inserta un ítem en el control, en la posición
QComboBox indicada por el primer parámetro. El texto del
ítem es el segundo.
insertItems(pos, items) QListWidget, Inserta varios ítems en la posición indicada por
QComboBox el primer parámetro. En el segundo debe ir un
conjunto, lista o tupla de cadenas.
isSortingEnabled() QListWidget Indica si los ítems del control están ordenados
por la propiedad sortingEnabled.
item(pos) QListWidget Cada ítem en la lista, se identifica con un
objeto de tipo QListWidgetItem. Al editar las
propiedades de alguno de estos objetos, estos
cambios se reflejan inmediatamente en el
QListView. Este método devuelve el

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 40
CENEAC - Programación con Python Nivel 2.

QListWidgetItem que se encuentra en la


posición indicada. En entero suministrado
como posición debe estar entre 0 y count() – 1.

Por ejemplo, para cambiar el texto del primer


ítem de un List Widget, usaríamos el siguiente
código:

self.lista.item(0).setText("Nuevo texto")

row(item) QListWidget Obtiene el número de fila de un ítem. Se debe


suministrar como parámetro, un objeto de tipo
QListWidgetItem.
selectedItems() QListWidget Devuelve una lista de elementos
QListWidgetItem, correspondientes a cada uno
de los elementos seleccionados en la lista, en
dado caso que la misma lo permita.
sortItems(modo) QListWidget Ordena los elementos de la lista.
sortItems() Opcionalmente, puede pasar un parámetro que
indicará la forma en la que se ordenarán los
elementos. Puede suministrar cualquiera de los
siguientes parámetros:
 Qt.AscendingOrder: Se organizarán en
orden ascendente.
 Qt.DescendingOrder: Se organizarán
en orden descendiente.
Si no especificamos argumentos, por defecto,
los elementos se ordenarán ascendientemente.
currentIndex() QComboBox Devuelve un entero con el número del ítem
seleccionado actualmente. Si no hay ninguno,
devuelve -1.

duplicatesEnabled() QComboBox Devuelve True si el control permite elementos


duplicados. False en caso contrario.
setDuplicatesEnabled( QComboBox Permite elementos duplicados si el parámetro
valor) es True. Si es False, no los permitirá.
currentText() QComboBox Devuelve el texto actual del control
isEditable() QComboBox Devuelve True si se puede escribir en el
control. False en caso contrario.
setEditable(valor) QComboBox Si se suministra True como parámetro, se
puede cambiar el texto del control
manualmente. Si se especifica False, no se
podrá.
maxVisibleItems() QComboBox Indica la cantidad máxima de ítems que pueden
verse en la lista desplegable a la vez. Si esta
cantidad es menor que la cantidad de
elementos, aparecerá una barra vertical a la
derecha de la lista.
setMaxVisibleItems(n QComboBox Indica la cantidad máxima de ítems visibles al
) desplegar el control.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 41
CENEAC - Programación con Python Nivel 2.

maxCount() QComboBox Indica la cantidad máxima de elementos que


puede haber en el control.
setMaxCount(n) QComboBox Establece la cantidad máxima de elementos
que puede haber en el control.

Nota: Si bien son muchos los métodos descritos acá, éstos no son más que una centésima parte de todos
los disponibles por todos los Widgets y otras clases no visibles. Se reitera la invitación a indagar en la
documentación de PyQt5 y si es entendido en C++, use la documentación oficial de Qt5.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 42
CENEAC - Programación con Python Nivel 2.

7. GESTIÓN DE BASES DE DATOS


RELACIONALES CON PYTHON
Tanto como una interfaz gráfica agradable, es importante la persistencia en los datos que ésta usa.
Vivimos en un mundo donde impera la necesidad de almacenar y leer mucha información, como
contactos, clientes, configuraciones, datos personales, financieros, estadísticos, etc.
Afortunadamente, Python nos ofrece una forma simple de acceder a una base de datos, totalmente
compatible con Qt Framework. Antes de pasar al código necesario para ello, es importante que
conozcamos algunos conceptos.

7.1. Bases de datos centralizadas y distribuidas


En el curso utilizaremos una base de datos centralizada, llamada MySQL Server cuyo motor se denomina
Inno DB. Una base de datos centralizada es aquella que utiliza los recursos de una única máquina para
funcionar. Las máquinas clientes, se conectan a la máquina que corre el servidor de base de datos, y le
solicitan consultas y modificaciones. Las ventajas de una base de datos centralizada, son muchas: evita la
inconsistencia de datos al evaluar cada petición y concentrar todos los datos en un mismo lugar; permite el
acceso a la base de datos desde muchos sitios a la vez, permite el acceso remoto a la base de datos.
También conoceremos la forma de utilizar una base de datos distribuida. Usaremos SQLite. Un gestor
muy popular, rápido y ligero. Las ventajas de una base de datos distribuida, radican en la velocidad de
reacción del motor de base de datos, la portabilidad y la migración de los datos.

7.2. Conectar con MySQL Server desde Python


Para versiones antiguas de Python, MySQL Server proporcionaba su propio conector. Para la fecha de
publicación de este manual, aún no existe una versión del conector de MySQL compatible con Python 3,
sin embargo, la comunidad de Python desarrolló PyMySQL, un conector alternativo y de alto rendimiento,
para MySQL y MariaDB. En el tema 2, indicamos la forma de instalar el gestor y esta biblioteca.
Para conectarnos a MySQL necesitamos que éste esté en ejecución, por defecto se iniciará junto a su
sistema operativo. Necesitamos también un usuario válido, su contraseña y (opcionalmente) una base de
datos creada. Se puede establecer una conexión con MySQL y crear una nueva base de datos, con el
siguiente código:
Ejemplo 14: Conexión con una base de datos
import pymysql.cursors

connection = pymysql.connect(host='localhost',
user='usuario',
password='contraseña',
cursorclass=pymysql.cursors.DictCursor)

cursor = connection.cursor()
sql = "CREATE DATABASE NombreBD"
cursor.execute(sql)
connection.commit()
connection.close()
Este es todo el código necesario para conectar Python con MySQL, crear una base de datos y cerrar la
conexión. Veamos la descripción de cada parte de este código:
import pymysql.cursors

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 43
CENEAC - Programación con Python Nivel 2.

Para poder utilizar el conector, debemos incluir pymysql.cursors en nuestro módulo:


conexion = pymysql.connect(
host='localhost',
user='usuario',
password='contraseña',
cursorclass=pymysql.cursors.DictCursor)
Debemos crear una variable nueva que almacenará nuestra conexión. Esta variable se crea llamando al
método connect, presente en pymysql. Debemos suministrar cuatro datos en el llamado, host es la
dirección del servidor; puede ser un nombre de dominio o puede ser una IP. El dominio localhost apunta a
nuestra propia máquina, es decir, que se conectará al servidor que esté corriendo en local. Si queremos
conectarnos a una base de datos en otra PC, debemos indicar la dirección IP correspondiente.
El parámetro user debe recibir un nombre de usuario válido. El usuario común es root, aunque puede crear
usuarios adicionales en su sistema. Para ello es recomendable, pero no indispensable, tener MySQL
Workbench instalado. Todo usuario posee una contraseña. Ésta se especifica en el parámetro password.
Luego, debemos indicar la clase encargada de procesar las peticiones a la base de datos. De esto se
encargará DictCursor.

Nota: Hay un parámetro llamado “db”, en el que debe suministrar un nombre de una base de datos a la
que el usuario que introdujo, tenga acceso. Solo por ser la primera vez que ejecutamos una conexión a
MySQL, se permite que no se pase este parámetro, pero ya que tenemos una base de datos creada, es
lógico suministrarla en el parámetro db para poder realizar modificaciones y consultas en ella.

cursor = conexion.cursor()
Se crea un nuevo cursor para la conexión
sql = "CREATE DATABASE NombreBD"
Creamos una cadena con la sentencia SQL a ejecutar
cursor.execute(sql)
Ejecutamos la sentencia
conexion.commit()
Guardamos los cambios en la base de datos
conexion.close()
Cerramos la conexión

7.3. Modificaciones
En SQL existen sentencias de modificación y consulta. Entre las sentencias de modificación, encontramos
a UPDATE, DROP, CREATE, INSERT, DELETE… etc. Las sentencias de modificación realizan
cambios en la base de datos y no regresan ningún resultado.
Al ejecutar una modificación, debemos subirla al servidor a través de un commit. Tenga en cuenta que esta
modificación puede fallar por diversos factores (Permisos de usuario insuficientes, errores de sintaxis,
identificadores inválidos, errores lógicos, conexión de red… etc.), y en caso de que esto suceda,
PyMySQL generará una excepción que, de no ser controlada, terminará abruptamente la ejecución de
nuestra aplicación. Ergo, es importante encerrar nuestras rutinas de acceso y modificación, en un bloque
try, en pro de evitar situaciones indeseadas.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 44
CENEAC - Programación con Python Nivel 2.

Para ejecutar una modificación, debemos iniciar sesión en el servidor, a través de un usuario y una
contraseña válidos, ejecutar las sentencias que deseemos, luego subir los cambios al servidor y cerrar la
conexión.
Ejemplo 15: Creación de una tabla en Python
import pymysql.cursors

connection = pymysql.connect(host='localhost',
user='ceneac',
password='clave',
db='ceneac',
cursorclass=pymysql.cursors.DictCursor)

cursor = connection.cursor()
try:
sql = """
CREATE TABLE clientes (
id INT NOT NULL AUTO_INCREMENT,
nombre VARCHAR(45) NOT NULL,
apellido VARCHAR(45) NOT NULL,
edad INT(3) NOT NULL,
rif VARCHAR(15) NOT NULL,
direccion VARCHAR(512) NULL,
PRIMARY KEY (id),
UNIQUE INDEX rif_u (rif ASC));
"""
cursor.execute(sql)
connection.commit()
except:
pass
finally:
connection.close()

Este código genera una nueva tabla en la base de datos llamada “ceneac”, siempre que ésta no exista. Note
que debe haber una base de datos con ese nombre para que la sentencia sea exitosa. La tabla tiene el
siguiente formato:
Columna Tipo Características
id Entero No puede ser NULL, clave primaria,
autoincrementable
nombre Alfanumérico No puede ser NULL
apellido Alfanumérico No puede ser NULL
edad Entero No puede ser NULL
rif Alfanumérico Único, no puede ser NULL
Dirección Alfanumérico

Si la ejecución de la sentencia no fue exitosa, se ejecutará el código debajo de except. En este caso no
hemos tomado acciones al respecto, pero de hacerlo, es allí donde debemos colocar el código necesario
para responder a los errores que pueda generar la sentencia SQL.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 45
CENEAC - Programación con Python Nivel 2.

Nota: Es recomendable que utilice comillas triples (""") en sus sentencias, para evadir el uso de
caracteres de escape innecesarios.

7.4. Consultas
Las consultas son un poco más complejas, pues son sentencias que devuelven algún tipo de contenido,
expresado en registros y columnas. Las sentencias que regresan datos, son SELECT, DESC (para
descripciones, no para ordenar), SHOW… etc.
Veamos cómo realizar consultas:
Ejemplo 16: Consultas a una base de datos desde Python
import pymysql.cursors
import pymysql.err
connection = pymysql.connect(host='localhost',
user='ceneac',
password='clave',
db='ceneac',
cursorclass=pymysql.cursors.DictCursor)
cursor = connection.cursor()
try:
sql = """
SELECT * FROM clientes WHERE edad > 22 ORDER BY apellido ASC
"""
cursor.execute(sql)
registro = cursor.fetchone()
while (registro != None):
print(registro['nombre'], registro['apellido'], registro['rif'])
registro = cursor.fetchone()

except pymysql.err.Error as error:


print(error)
finally:
connection.close()

Hay varias cosas nuevas en este código, vamos a analizarlo línea por línea.

import pymysql.cursors
import pymysql.err
Incluimos otro módulo más, llamado “err”. Este módulo contiene la definición de errores de PyMySQL.

connection = pymysql.connect(host='localhost',
user='ceneac',
password='clave',
db='ceneac',
cursorclass=pymysql.cursors.DictCursor)
La conexión a la base de datos es idéntica.

cursor = connection.cursor()
try:

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 46
CENEAC - Programación con Python Nivel 2.

sql = """
SELECT * FROM clientes WHERE edad > 22 ORDER BY apellido ASC
"""
Se solicita una consulta a la tabla clientes, se tomarán todos aquellos cuya edad sea mayor a veintidós y se
ordenarán los resultados por apellido de forma ascendiente.

cursor.execute(sql)
Se ejecuta la consulta

registro = cursor.fetchone()
Se crea una nueva variable llamada registro y se le asigna el resultado de fetchone. Este método devuelve
un diccionario con un único registro. En este caso, el primero. Devuelve el diccionario y quita el registro
del cursor. Ahora registro contiene una fila completa. Cada clave de este diccionario, es el nombre de una
culumna de la base de datos. Es decir, si queremos obtener el valor del campo “dirección”, debemos usar:
Registro['direccion']
Ahora bien, si quisiéramos obtener no uno, sino todos los registros que coinciden con la consulta,
debemos usar fetchall. Este método nos devuelve una lista de diccionarios. Cada uno de los elementos de
la lista es un registro. Si solo queremos obtener algunos, usaríamos fetchmany. Este método recibe un
entero como parámetro, indicando la cantidad de registros que se tomarán de la consulta. Al igual que
fetchone, saca del cursor, todos los registros que se devolvieron. Si la consulta regresa con 1000 registros
y llamamos a fetchmany con 100, quedarían 900 en el cursor. Al igual que fetchall, regresa un diccionario
con las coincidencias

Nota: Cuidado con el uso de fetchall. Si la cantidad de registros es grande, puede tardar mucho tiempo la
consulta y gastar una enorme cantidad de recursos.
Si se llama a fetchone o a fetchall, y no hay registros para mostrar, la función regresa None.

while (registro != None):


print(registro['nombre'], registro['apellido], registro['rif'])
registro = cursor.fetchone()
Mientras el registro sea diferente de None, se muestra en pantalla el nombre, apellido y RIF del cliente.
Luego, se avanza al siguiente registro, con la función fetchone. Recordemos que cada vez que se llama a
esta función, se saca del cursor, el registro solicitado.

except pymysql.err.Error as error:


print(error)
Tomamos el error que nos da PyMySQL y lo mostramos en pantalla antes de salir

finally:
connection.close()
Finalmente, cerramos la conexión con la base de datos.

Nota: None indica la ausencia de un valor determinado. Es compatible con todas las variables e indica un
identificador sin tipo ni valor.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 47
CENEAC - Programación con Python Nivel 2.

7.5. Acceso a una base de datos SQLite


Como mencionamos páginas atrás, SQLite es una base de datos distribuida. Esto tiene la ventaja de que el
acceso a ella, no dependerá de un intermediario, por lo que tanto lectura como escritura, se realizarán de
forma mucho más rápida que una base de datos centralizada.
A diferencia de MySQL, SQLite almacena la base de datos en un único archivo, cuya ubicación debe ser
conocida por el programa al momento de utilizarla, tanto como para MySQL es obligatorio conocer IP del
servidor.

7.6. Cargar o crear una base de datos SQLite y operar sobre ella
El procedimiento no es muy distinto al utilizado en MySQL, por lo que son muy pocas las cosas nuevas
que tendremos que memorizar. El código utilizado para este fin es parecido al anterior, veamos un
ejemplo.
Ejemplo 17: Operar con SQLite desde Python
import sqlite3
conexion = sqlite3.connect("ejemplo.db")
cursor = conexion.cursor()

cursor.execute("""
CREATE TABLE IF NOT EXISTS Persona (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
nombre VARCHAR(45) NOT NULL,
apellido VARCHAR(45) NOT NULL);
""")

cursor.execute("INSERT INTO Persona(nombre, apellido) VALUES ('Luis', 'Martin')")


cursor.execute("INSERT INTO Persona(nombre, apellido) VALUES ('Petra', 'Flores')")
cursor.executescript ("""
INSERT INTO Persona(nombre, apellido) VALUES ('Alejandro', 'Jiménez');
INSERT INTO Persona(nombre, apellido) VALUES ('Marta', 'Pérez');
INSERT INTO Persona(nombre, apellido) VALUES ('Steven', 'Jobs');
""")
consulta = cursor.execute("SELECT * FROM Persona ORDER BY apellido")
for registro in consulta.fetchall():
print(registro[0], registro[1])

conexion.commit()
cursor.close()
conexion.close()

Veamos una explicación de las partes nuevas.


import sqlite3
conexion = sqlite3.connect("ejemplo.db")
cursor = conexion.cursor()
Debemos importar el módulo sqlite3 para poder utilizar sus funciones, siendo connect, una de ellas. Al
llamar a connect, debemos pasar como parámetro, el nombre de una base de datos. Si esta existe en el
directorio, se abre, sino, se crea.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 48
CENEAC - Programación con Python Nivel 2.

Nota: Puede escribir :memory: entre las comillas de la cadena suministrada a connect. Esto es para que
la base de datos resida en memoria y no en disco. Todo cambio realizado a ella, se perderá una vez
culminado el programa.

Luego se crea un único cursor para operar sobre la base de datos.


cursor.execute("""
CREATE TABLE IF NOT EXISTS Persona (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
nombre VARCHAR(45) NOT NULL,
apellido VARCHAR(45) NOT NULL); """)
Se ejecuta una sentencia para crear una tabla
cursor.execute("INSERT INTO Persona(nombre, apellido) VALUES ('Luis', 'Martin')")
cursor.execute("INSERT INTO Persona(nombre, apellido) VALUES ('Petra', 'Flores')")
Ejecutamos dos inserciones en la tabla creada
cursor.executescript ("""
INSERT INTO Persona(nombre, apellido) VALUES ('Alejandro', 'Jiménez');
INSERT INTO Persona(nombre, apellido) VALUES ('Marta', 'Pérez');
INSERT INTO Persona(nombre, apellido) VALUES ('Steven Paul', 'Jobs');
""")
Podemos ejecutar varias sentencias con el método executescript
consulta = cursor.execute("SELECT * FROM Persona ORDER BY apellido")
for registro in consulta.fetchall():
print(registro[0], registro[1])
Se realiza una consulta simple y se recorren los resultados para mostrar el ID y el nombre solamente.
conexion.commit()
cursor.close()
conexion.close()
Se guardan los cambios en la base de datos, se cierra el cursor y también la conexión.
Si todo sale bien, se mostrará la siguiente salida:
python.exe D:/PROYECTOS_PROGRAMACION/Python/CursoN2/BD/DB_SQLite.py
2 Petra
3 Alejandro
5 Steven Paul
1 Luis
4 Marta

Y por supuesto, se creará la base de datos en disco.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 49
CENEAC - Programación con Python Nivel 2.

Manual de programación en

Ejemplos y ejercicios

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 50
CENEAC - Programación con Python Nivel 2.

8. EJEMPLOS RESUELTOS

En esta sección de la guía aprenderemos a través de ejemplos completos, algunas acciones de utilidad.
Como se podrá imaginar, Qt es mucho más grande que el contenido programático de este texto, por lo que
acá veremos la forma de realizar algunos algoritmos comunes a través de algunas sentencias que no hemos
tenido la oportunidad de revisar anteriormente.
En estos ejemplos encontrará clases, funciones y métodos nuevos y útiles para ciertas tareas.
Ejemplo 18: Solicitar 5 números en 5 campos de texto y calcular su promedio.

Requisitos: crear un QMainWindow, con cinco campos QLineEdit, llamados “n1”, “n2”, “n3”, “n4” y
“n5”. Un QPushButton llamado “calcular” y un QLabel llamado “resultado”.
Código:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic

class Ventana(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("Ejemplo18.ui", self)
for i, j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)
def obtener_promedio(self):
num1 = int(self.n1.text())
num2 = int(self.n2.text())
num3 = int(self.n3.text())
num4 = int(self.n4.text())
num5 = int(self.n5.text())
return (num1 + num2 + num3 + num4 + num5) / 5

def eventFilter(self, control, evento):


if evento.type() == QEvent.MouseButtonPress and control == self.calcular:
if evento.button() == Qt.LeftButton:
try:
self.resultado.setText(str(self.obtener_promedio()))
except BaseException as error:
self.resultado.setText("ERROR")
print("ERROR: ", error.args)
return QWidget.eventFilter(self, control, evento)

if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = Ventana()
mi_ventana.show()
sys.exit(app.exec())

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 51
CENEAC - Programación con Python Nivel 2.

Ejemplo 19: Mostrar las coordenadas actuales del cursor del mouse en la pantalla.
Requisitos: crear un QMainWindow con un QLabel llamado “coordenadas” con su propiedad
mouseTracking en True y agrandado para toda la ventana.
Código:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic

class Ventana(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("Ejemplo19.ui", self)
for i, j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)

def eventFilter(self, control, evento):


if evento.type() == QEvent.MouseMove:
try:
self.coordenadas.setText("X: " +
str(evento.x()) + ", Y: " + str(evento.y()))
except BaseException as error:
print(error.args)

return QWidget.eventFilter(self, control, evento)

if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = Ventana()
mi_ventana.show()
sys.exit(app.exec())

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 52
CENEAC - Programación con Python Nivel 2.

Ejemplo 20: Crear un formulario adicional en tiempo de ejecución y enviarle un valor


Requisitos: crear un QMainWindow con un PushButton llamado “lanzar” y un QDialog (Diseñar en Qt
Designer tal como un QMainWindow, solo que seleccionando Dialog desde el menú de creación). Éste
tendrá un QLabel llamado “texto”.
Código:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic

class Secundario(QDialog):
def __init__(self, texto):
QDialog.__init__(self)
uic.loadUi("Ejemplo20b.ui", self)
self.texto.setText(texto)
class VentanaPrincipal(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("Ejemplo20a.ui", self)
for i, j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)

def eventFilter(self, control, evento):


if evento.type() == QEvent.MouseButtonPress and control == self.lanzar:
otro_form = Secundario("Texto de prueba")
otro_form.exec()

return QWidget.eventFilter(self, control, evento)

if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = VentanaPrincipal()
mi_ventana.show()
sys.exit(app.exec())

Nota: Puede pasar cualquier objeto al constructor de un Diálogo. Éstos se utilizan para mostrar ventanas
adicionales a la principal. Por cada diálogo debe existir una clase que lo atienda, tanto como la tiene una
ventana QMainWindow.
Como sugerencia, le invito a separar cada clase que contenga una ventana, en un módulo distinto, en pro
de facilitar la lectura de su código.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 53
CENEAC - Programación con Python Nivel 2.

Ejemplo 21: La fórmula para convertir grados centígrados a grados Fahrenheit es:
. Escribir un programa que permita convertir temperaturas
ingresadas de ºC a ºF y viceversa a medida que se escribe.

Requisitos: un QMainWindow con dos QDoubleSpinBox llamados “centígrados” y “fahrenheit”, con su


propiedad máximum puesta en diez millones y mínimum en menos diez millones.
Código:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic

class VentanaPrincipal(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("Ejemplo21.ui", self)
for i, j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)

def eventFilter(self, control, evento):


if evento.type() == QEvent.KeyRelease:
if control == self.centigrados:
self.fahrenheit.setValue(self.centigrados.value() * 1.8 + 32)
elif control == self.fahrenheit:
self.centigrados.setValue((self.fahrenheit.value() - 32) / 1.8)

return QWidget.eventFilter(self, control, evento)

if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = VentanaPrincipal()
mi_ventana.show()
sys.exit(app.exec())

Nota: En este ejemplo se utiliza un control no tratado hasta ahora. Es poco común, pero para estos casos
es el indicado. QDoubleSpinBox es un control que sirve solo para almacenar números reales. No tiene
una propiedad llamada text pero tiene una llamada value que devuelve el valor contenido en el control y
este valor será de tipo real. Por su parte, setValue modifica el valor del control. Así, mientras el usuario
escriba en uno, se cambia el otro. Un ejemplo corto, pero muy útil e ingenioso.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 54
CENEAC - Programación con Python Nivel 2.

Ejemplo 22: Centrar una ventana en pantalla


Requisitos: un QMainWindow
Código:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic

class VentanaPrincipal(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("Ejemplo22.ui", self)
self.centrar_ventana()
for i, j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)

def centrar_ventana(self):
ancho_pantalla = QApplication.desktop().width()
alto_pantalla = QApplication.desktop().height()
ancho_ventana = self.width()
alto_ventana = self.height()
xdef = (ancho_pantalla // 2) - (ancho_ventana // 2)
ydef = (alto_pantalla // 2) - (alto_ventana // 2)
self.move(xdef, ydef)

def eventFilter(self, control, evento):


return QWidget.eventFilter(self, control, evento)
if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = VentanaPrincipal()
mi_ventana.show()
sys.exit(app.exec())

Nota: La clase QApplication tiene un método llamado desktop que nos devuelve información sobre el
escritorio. Entre esta información, puede estar el ancho y alto de la pantalla, expresado en píxeles.
El resto es fácilmente comprensible. Se obtiene el alto y ancho de la pantalla, luego el de la ventana y
luego mediante cálculos simples, hallamos el centro para la ventana, teniendo en cuenta que las
coordenadas que se le pasarán a move, pertenecen a la esquina superior derecha de la ventana.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 55
CENEAC - Programación con Python Nivel 2.

Ejemplo 23: Cargar un archivo de texto desde el disco y mostrarlo. El archivo debe
seleccionarlo el usuario con un cuadro de diálogo.

Requisitos: un QMainWindow con un QPlainTextEdit llamado “txtArchivo” y un QPushButton llamado


“btnAbrir”
Código:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic

class VentanaPrincipal(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("Ejemplo23.ui", self)
for i, j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)

def eventFilter(self, control, evento):


if evento.type() == QEvent.MouseButtonPress and control == self.btnAbrir:
if evento.button() == Qt.LeftButton:
nombre_archivo = QFileDialog.getOpenFileName(self,
caption="Abrir archivo", filter="*.txt")
archivo = open(nombre_archivo[0]).read()
self.txtArchivo.setPlainText(archivo)
return QWidget.eventFilter(self, control, evento)

if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = VentanaPrincipal()
mi_ventana.show()
sys.exit(app.exec())
Otra clase importante: QFileDialog. Esta clase muestra en pantalla un diálogo para abrir o cerrar archivos.
El método que utilizamos es getOpenFileName. Éste muestra un diálogo para abrir archivos y podemos
personalizar el filtro del archivo y el título del diálogo desde sus parámetros.
El método nos devuelve una tupla con dos elementos. El primero es el archivo seleccionado con su
respectiva extensión y el segundo es solo la extensión del mismo. Se abre el archivo con el método open y
luego con read leemos el contenido entero, para posteriormente, guardarlo en un QPlainText.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 56
CENEAC - Programación con Python Nivel 2.

Ejemplo 24: Añadir ítems a una lista y responder a su selección.

Requisitos: Un QMainWindow con un QListWidget llamado “lista”, un QLineEdit llamado “ítem”, un


QLabel llamado “seleccionado” y un QPushButton llamado “agregar”.
Código:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic

class VentanaPrincipal(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("Ejemplo24.ui", self)
self.layout = QVBoxLayout(self)
for i, j in vars(self).items():
if isinstance(j, QWidget):
j.installEventFilter(self)

self.lista.itemClicked.connect(self.ItemClick)

def ItemClick(self, item):


if not self.lista.currentIndex() == -1:
self.seleccionado.setText(self.lista.currentItem().text())

def eventFilter(self, control, evento):


if evento.type() == QEvent.MouseButtonPress and evento.button() == Qt.LeftButton:
if control == self.agregar:
if not self.item.text() == "":
self.lista.addItem(self.item.text())

return QWidget.eventFilter(self, control, evento)

if __name__ == "__main__":
app = QApplication(sys.argv)
mi_ventana = VentanaPrincipal()
mi_ventana.show()
sys.exit(app.exec())

Nota: Este ejercicio no solo demuestra el uso de un control de lista. También ilustra cómo asociar un
evento de una lista a través del método connect. Cuando se hace esto, el método suministrado a connect
es llamado cada vez que ocurra el evento; en este caso, cuando se haga clic en un ítem.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 57
CENEAC - Programación con Python Nivel 2.

9. EJERCICIOS PARA RESOLVER

1. Realice una calculadora con las funciones matemáticas básicas y algunas otras de interés: Suma,
resta, multiplicación, división, módulo, potencia, raíz cuadrada y cúbica.
2. Haga un sistema de ingreso que permita acceder a las funciones del programa, solo cuando el
usuario se haya autenticado correctamente
3. Realice un programa que permita obtener la matriz inversa de una matriz NxM suministrada por el
usuario a través de cualquier método conocido.
4. Programe un editor de texto. Si utiliza QsciScintilla, puede tener resaltado de sintaxis.
5. Cree un programa de gestión de inscripciones. Éste debe tener ingreso de datos de nuevos
estudiantes, consulta de datos almacenados, modificación, eliminación y actualización de notas.
6. Realice un sistema de gestión de bases de datos, que permita acceder a las tablas de una base en
concreto y realizar consultas y cambios a petición del usuario
7. A cualquiera de los programas anteriores, agregue un sistema que permita almacenar las
configuraciones del mismo y que éstas persistan luego de cada ejecución.
8. Diseñe una interfaz sin barra de título, con algún diseño propio que la simule, y que, al arrastrar el
cursor sobre ella, se pueda desplazar la ventana, tal cual como si la barra de título existiera.
9. Lea a través de dos cuadros de texto, las coordenadas de una casilla de un tablero de ajedrez en la
que se encuentra un caballo y muestre en una lista, las coordenadas de las casillas a las que ese
caballo podría desplazarse en un turno. Puede utilizar varios QCheckBox para simular las casillas.
10. Simule un sistema de ventas de lotería. Genere un reporte en un archivo de texto, sobre todos los
números vendidos, día y fecha de la venta.

Material elaborado por CENEAC Producciones, C.A. Prohibida su reproducción total o parcial sin autorización del Autor. 58

También podría gustarte