Introducció

En aquest post es podrà llegir els passos que cal seguir per a construir el plugin ‘Taula Resum’ per a QGIS.

En el plugin ‘TaulaResum’ cal destacar el canvi de filosofia que s’ha produït amb el canvi de GeoMedia, el qual treballa amb bases de dades locals, al QGIS. En canvi amb aquest últim hem passat a treballar amb un topologia client-servidor, que permet que tots els usuaris que disposin de les credencials podran accedir a les bases de dades sempre que vulguin i des de qualsevol lloc. I només el cal tenir el mòdul QGIS amb el mòdul instal·lat i podran treballar.

Sempre que fem referència a qualsevol element de l’entorn de programació o QGIS, aquest és explicat en el post sobre ‘com preparar l’entorn’.

Procés de creació

Disseny de la interfície

El primer que vam fer va ser la creació de la interfície del plugin. Un cop hem creada l’estructura del plugin amb el ‘Plugin Builder’, vam obrir l’arxiu amb format *.ui amb el Qt Designer i començarem amb la creació. Primer va caldre posar les pestanyes més exteriors (QTab Widget) i dimensionar-lo de manera adequada. Al voltant, vam afegir els elements que ajudaran a escollir els filtres, els mètodes de treball, l’elecció de la connexió i els botons per crear la taula i sortir. Un costum que tenim és el de posar una etiqueta amb la versió de la plugin, ja que ajuda a la identificació de quines són les funcions que pot tenir un plugin. Els plugins poden patir diferents actualitzacions i les funcions poden variar. En el cas de que hi hagi un error en una versió que no és la més recent, l’etiqueta facilita la detecció de l’error i es pot corregir ràpidament. El resultat de tot això es pot veure a la figura 1.

p1
Figura 1

Un vegada fet, vam afegir els elements de dintre les cinc pestanyes dels filtres. Finalment, el que vàrem fer és donar-li un nom que ajudi a la identificació de cada element interactiu de la interfície. Aquest serà el nom que utilitzarem per poder-hi interactuar dins el codi principal que controlarà el plugin. A la figura 2 es pot veure com quedaria la finestra amb la pestanya principal omplerta.

p2
Figura 2

Recomanem que siguin el més explícits possible ja que es podran evitar errades i també ajudaran a facilitar la comprensió del codi, com per exemple ‘ComboConnexio’ en referencia a la pestanya desplegable on s’hi indicarà la connexió que volem escollir.

Interacció amb les Bases de Dades

Per a poder realitzar qualsevol acció sobre la base de dades cal primer saber el nom d’usuari, nom de la base de dades, servidor i contrasenya. És recomanable guardar aquestes dades en variables globals i aconseguirem accedir-hi des de qualsevol funció en qualsevol moment. També cal fer l’import de la llibreria psycopg2 (import psycopg2) al principi del codi.

Per establir la connexió hem utilitzat el codi següent:

#Connexio
nomBD = nomBD1.encode('ascii','ignore')
usuari = usuari1.encode('ascii','ignore')
servidor = host1.encode('ascii','ignore')
contrasenya = contra1.encode('ascii','ignore')
try:
  estructura="dbname='"+nomBD+"' user='"+usuari
  +"' host='"+servidor+"' password='" + contrasenya + "'"
  conn = psycopg2.connect(estructura)
  cur = conn.cursor()
  cur.execute(Sentencia_sql)
  resultat = cur.fetchall()
  conn.close()

Utilitzarem la comanda execute(<sentencia SQL>) per realitzar la consulta. Per poder passar els resultats i per poder-los tractar utilitzarem la comanda fetchall() que retorna una matriu amb tots ells. És important tancar la connexió un cop haguem fet les consultes necessàries.

En el cas que ens ocupa, hi ha tres pestanyes del grup de pestanyes principals que necessiten llegir dades de la BD i exposar-les en els seus respectius camps. Com per exemple en la pestanya ‘Estudis’ hi ha un requadre amb una llista (QListWidget) on cal llistar-hi tots els estudis que hi pot haver i que tenim emmagatzemats a la taula del Padró. El que busquem nosaltres és una consulta que ens retorni els diferents tipus d’estudi que hi ha i ho hem resolt amb la sentencia SQL següent:

select distinct("HABNIVINS"),"NINDESCRI" from "public"."Padro" order by 2;

El camp “HABNIVINS” és l’identificador de l’estudi i el “NINDESCRI” és el nom de l’estudi que apareixerà al requadre de la llista. L’identificador de l’estudi el vincularem a l’estudi per mitjà del ToolTip(), que posteriorment ens facilitarà la construcció de la consulta que l’usuari desitja.

Connexió dels botons

Per poder vincular i recollir els estats dels elements de la interfície cal fer els següents passos. Primer de tot cal fer from TaulaResum_dialog import TaulaResumDialog per tal de poder vincular el fitxer de la interfície amb el codi.

Aleshores, a la funció init(), que ja ve creada pel Plugin Builder, hi posem les següents comandes:

self.dlg = TaulaResumDialog()
self.dlg.btoNACIONALITAT.toggled.connect(self.on_click_MarcarBotoNACIONALITAT)
self.dlg.comboConnexions.currentIndexChanged.connect(self.on_Change_ComboConn)

El primer inicialitza el diàleg amb el què hem d’interaccionar. Les altres dos activen les seves funcions respectives cada vegada que el valor que tinguin variï. Segons el tipus d’element que sigui, es pot canviar l’aparença o carregar elements per pantalla.

Cada element de la interfície ha de tenir una funció vinculada a ell per tal de que el codi sigui capaç de veure en quin estat està.

Programació dels efectes dels botons

Cada vegada que l’usuari interaccioni amb un dels elements de la interfície es produirà un efecte. En aquest apartat s’introduirà un exemple d’aquest tipus de comportament. Per l’exemple utilitzarem el codi següent:

def on_click_MarcarBotoEDAT(self, clicked):
if clicked:
  self.dlg.btoEDAT.setStyleSheet('background-color: #7fff7f')
  self.dlg.GrupPestanyes.setCurrentIndex(0)
else:
  self.dlg.btoEDAT.setStyleSheet('background-color:rgb(227,227,227)')

Aquesta funció es dedica a controlar l’aspecte del botó del filtre d’Edat. Si és clicat, canvia de color de fons i mostra la pestanya del filtre d’edat per tal que l’usuari esculli els paràmetres que vol analitzar. Altrament, li torna a posar el color de desactivat.

A més a més, cal tenir en compte que els elements de la interfície tenen memòria i que un cop els hi canviem l’estat, creem la taula i tanquem el plugin, una vegada el tornem a obrir, conserven el seu estat anterior. Això fa necessària una funció que posi aquests elements en el seu estat inicial cada vegada el que el plugin s’obri i s’utilitzi.

En el nostre cas, la majoria d’elements de la interfície tenen efectes molt senzills com el que hem explicat fa un moment però hi ha un botó que realitza una funció més complexa: crear la taula resum. Aquesta funció recull totes les dades que l’usuari ha introduït sobre els filtres que desitja analitzar, comprova que no hi hagi cap error o que falti alguna dada, es connecta amb la base de dades i escriu el resultat en fitxers de text .csv per a que l’usuari els pugui utilitzar sempre que vulgui.

Un altre punt important és el control d’errors. Cada cop que es produeixi un resultat no esperat s’ha controlar i avisar a l’usuari del que ha passat i indicar-li els passos per corregir l’errada. En el nostre cas, els errors més comuns es produeixen a l’hora de crear les consultes: l’usuari no introdueix correctament les dades de la consulta. Però també pot ser que la connexió no estigui disponible o que l’usuari no tingui els permisos adequats de lectura.

Quan es tracta d’un error relacionat amb la connexió s’adverteix a l’usuari per mitjà d’una etiqueta que n’indica l’estat. En el cas de tenir problemes amb la consulta, apareixen finestres amb el missatge d’error.

Prova del plugin

Una vegada hem programat totes les funcions, cal comprovar que els resultats són els esperats. Per fer-ho, cal que utilitzem el GeoMedia amb el plugin que s’utilitzava anteriorment i comprovar que si posem les mateixes variables d’entrada obtenim el mateix resultat.

Cal que el procés sigui exhaustiu perquè cal revisar cadascuna de les funcions que s’han implementat. S’han de fer totes les combinacions possibles i comprovar que el número de resultats ha sigut igual. En el cas que no ho sigui, s’han de comparar els codis i veure el punt on difereixen.