MacGenda con PyQT 5

Introducción
Parece ser que Python se está poniendo de moda. Debido a la IA y al papel que este lenguaje de programación juega en este entorno, cada vez más personas aterrizan en este mundillo. Yo también, aunque hace años que no desarrollo nada. Mi último programa lo realicé en Linux con Gambas 3 y ya ha llovido desde aquello. Con anterioridad, había hecho alguna cosilla en C, lo que puede llevar a la imaginación del lector de este texto, casi a la prehistoria. Bien, en cualquier caso, el asunto es que me propuse dar mis primeros pasos con Python y QT, así que, no hay más pretensión aquí, que contar grosso modo cómo fue esta experiencia.
Pasos previos
Debido a que el que suscribe, no tiene ni idea de python, el primer paso, antes de cualquier otra cosa, comienza con la instalación del software, así que, en el momento de redactar esto, instalé la versión 3.13.0 de python además de QT 5. Así mismo, me di a la tarea de localizar algunos tutoriales y libros que tocaran la correspondiente temática, iniciando, como es obvio, con el clásico "Hola mundo".
Como la cosa, poco a poco iba tomando forma, decidí dar un paso más y actualizarme en el asunto, de manera que resultara algo más entretenido y con miras al futuro, el tema de la programación. Entonces me decanté por instalar QT6 y el ambiente "libre" de QT Creator y QT Designer, aunque no iba a ser utilizado en primera instancia. Digamos, entonces, que me gustó el tema y me metí de lleno en el asunto, aunque eso sea otra historia.
Escribiendo la interfaz y trabajando con SQLite 3
El planteamiento para este pequeño proyecto, consistió en desarrollar una Agenda simple que guardara y leyera los datos de una base de datos SQLite. Por lo tanto, se trató de una aplicación local con una funcionalidad básica (Guardar y tener a su disposición para consulta, datos básicos de un número indeterminado de contactos). El código inicial y real, es el que se puede apreciar en la captura de pantalla de la derecha. Se trata de la primera versión y, como hacen los poetas, el asunto amerita revisiones constantes y cambios sutiles.
La base de datos inicial, tampoco supone demasiada complicación. Si bien los pasos se pueden realizar a mano, decidí crear un script que me sirviera también para ir profundizando en el tema de python a la vez que me automatizara la tarea de su creación. Es importante señalar que SQLite 3 ya viene preinstalado en MacOS, así que, no hay que hacer nada, excepto ponerse a trabajar directamente.
Para quien no lo sepa, cosa que dudo, SQLite es una biblioteca de C que provee una base de datos ligera que no requiere un proceso de servidor separado, y permite acceder a la base de datos usando una variación no estándar del lenguaje de consulta SQL. Algunas aplicaciones pueden usar SQLite para almacenamiento interno. También es posible prototipar una aplicación usando SQLite y luego transferir el código a una base de datos más grande como PostgreSQL u Oracle.
En este punto de la cuestión, dispongo de la base de datos creada y del código inicial. No obstante, si se observa la primera captura de pantalla, es fácil observar que, si bien existe la llamada a sqlite con la opción import, no se realiza la conexión con ésta. En este punto del desarrollo, estoy pensando si realizar la conexión en automático, una vez llamado el programa, o realizar la conexión de forma diferente. En cualquier caso, ya tengo en mente la instrucción con = sqlite3.connect('agenda.db')
La documentación de python, en referencia a SQLite, también nos indica una cuestión interesante: la creación de la base de datos en memoria. Al parecer, esto se hace con la opción con = sqlite3.connect(":memory:"), sin embargo, para este proyecto, no aporta nada interesante, con la natural excepción, si cabe, de la experimentación.
Como se puede apreciar en el script de creación de la base de datos, las instrucciones son muy puntuales y precisas. No he considerado, por ejemplo, la posibilidad de algún error durante el proceso de creación de la base. La opción sqlite3.Error soluciona el asunto, pero como dije al principio, se trata del código inicial, donde busco una funcionalidad rápida debido, quizá, a mi falta de paciencia. Como dijo un cojo: "Todo se andará".
La interfaz
Como comenté en el apartado anterior, la interfaz se escribió utilizando texto puro y duro; es decir, no utilicé QT Designer. Los pasos los fui sacando de algunos libros y manuales que, para ser sincero, tenían ya cierta antigüedad. Esa fue otra de las razones por las cuales implementé QT 5, cuando a día de hoy, la última versión disponible es la 6.8. Consideré que, como la idea es aprender, la elección de versiones, así como el proceso, aunque más tardado, era el ideal para mis intereses.
Si se observa la imagen de la izquierda, el diseño de la interfaz requiere algunos ajustes. Sin embargo, incluye lo que considero fundamental para una agenda básica: Un cuadro para una fotografía, con botones para seleccionar la foto y eliminarla, los campos para los datos personales y, en la parte derecha, una lista en dónde aparecerán todos los contactos almacenados en la base de datos. Así mismo, incluí un botón de búsqueda, con la finalidad de que, si el número de contactos es considerable, puedan localizarse con dicha opción. Para finalizar, podemos ver los botones de guardar, editar, borrar y limpiar, que ineractúan con los datos de los contactos y SQLite.
A vueltas con el código
Durante el proceso de escribir código, surgieron varios problemas. La estructura en python resulta muy delicada, así que, como se podrá imaginar el lector, la pérdida de tiempo que supone "probar y corregir" es bastante. Específicamente, obtuve lo siguiente en un par de ocasiones: IndentationError: unindent does not match any outer indentation level, asunto referente a tabulaciones y/o espacios en el código, lo que me obligó a realizar revisiones exhaustivas, con lo que ello supone.
Otra de las cuestiones con las que me encontré, fue un error en la conexión a la base de datos. Tras muchas vueltas, lo pude solucionar moviendo la línea self.connect_to_database() antes de self.initUI() en el método init. Así mismo, tuve que añadir una comprobación en la carga de lista de contactos con la finalidad de que self.cursor no tuviera el valor None. Lo anterior, derivaba de un AttributeError que se mostraba al ejecutar el programa.
Por último, como se puede apreciar en la imagen de la derecha, se me olvidó añadir en la base de datos el campo referente a la fotografía, aunque, en su conjunto, fuera éste el menor de todos los males experimentados.
El resultado final
Solventados los problemas descritos y algunos otros cuyo análisis necesitaría más espacio en esta web, si me decidiera a comentarlos, concluí la MacAgenda. La imagen de la izquierda resulta, a mi criterio, bastante ilustrativa.
Los cambios finales, en esencia, son estéticos. El logo genérico que aparece entre la foto y la lista de contactos, se puede sustituir fácilmente, añadiendo una imagen de 250x250 alojada en la misma ruta que el ejecutable "agenda.py". El banner inferior, es simplemente una cuestión de "Artwork" también fácilmente reemplazable.
Cabe destacar que, inmerso en el código, se incluye una modificación del script que genera la base de datos. Es decir, cuando uno ejecuta el script de python que invoca a la agenda por primera vez, se valida si existe o no la base de datos y, en el supuesto de que no exista (como es lógico), la crea automáticamente.
Es probable que a día de hoy, este programilla tenga poca utilidad. Sin embargo, poder disponer de los datos de contacto que a uno le interesan, de forma local, sin depender de conexiones a internet, etc., puede resultar atractivo. En cualquier caso, he aprendido cosas nuevas, me he entretenido y eso para mí, es suficiente.