di  -  martedì 8 giugno 2010

Eccoci giunti al secondo appuntamento del percorso che ci porterà a costruire un basilare feed reader. Nella precedente puntata abbiamo visto come fare il parsing di un feed RSS attraverso l’utilizzo della libreria Universal Feed Parser. Oggi inizieremo a vedere le basi per la costruzione di una semplice interfaccia grafica per visualizzare i dati ottenuti. Le librerie grafiche utilizzate saranno le Qt4. Essendo Qt un framework nativo C++ e dovendolo integrare nel nostro progetto python utilizzeremo binding forniti dalla Riverbank computing, le PyQt.

Chi utilizza una distribuzione GNU/Linux debian based (per esempio Ubuntu) dovrà installare i pacchetti:

python-qt4
qt4-designer

Gli installer per Windows e MacOSX possono essere scaricati dal sito della Riverbank Computing.

DISEGNIAMO L’INTERFACCIA

Per prima cosa apriamo Qt Designer (programma per la costruzione di interfacce) e selezioniamo Main Window tra i template disponibili. Quello che ci troveremo avanti sarà una tipica finestra principale composta da un widget centrale, una barra dei menu ed una barra di stato.

Per semplicità utilizzeremo un widget per la visualizzazione degli elementi del feed (QTreeWidget).  In generale è sempre consigliabile utilizzare le view rispetto ai widget essendo le prime estremamente più flessibili. L’unico costo della prima soluzione è una logica implementativa più complessa che richiede la comprensione del pattern Model View Controller che esula dagli scopi di questa serie di post.

Per aggiungere il QTreeWidget è sufficiente trascinarlo dalla colonna di sinistra (Widget Box) all’interno della Main Window. Fatto questo possiamo modificare il numero di colonne del TreeWidget semplicemente facendo doppio click sopra al widget appena inserito.

Nello specifico inseriremo i campi “titolo”, “autore” e “commenti”. L’ultima cosa rimasta da fare prima di mettere da parte il designer è selezionare un layout. In questo caso selezionare un layout verticale od orizzontale è assolutamente indifferente visto che abbiamo inserito un solo widget.

Fatto questo possiamo salvare il file all’interno della cartella dei sorgenti del programma (mainwindow.ui).

COMPILIAMO L’INTERFACCIA

Il file salvato non è nient’altro che un file XML che contiene la descrizione dell’interfaccia. Tale file dovrà essere processato con il tool pyuic per generare automaticamente il codice python necessario alla creazione dell’interfaccia descritta.

Per compiere l’operazione è necessario invocare il tool da riga di comando:

pyuic4 ./mainwindow.ui -o ./mainwindowUi.py

Il file mainwindowUi.py non va mai modificato manualmente poichè verrà sovrascritto ad ogni modifica e ricompilazione del file .ui.

Compiuto questo passo abbiamo tutto il necessario per costruire la nostra applicazione grafica.

SCRIVIAMO IL CODICE DELL’APPLICAZIONE

Per avere una visione complessiva potete osservare il codice sorgente completo.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
# Import Qt modules
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# Import pyuic4 compiled GUI
from mainwindowUi import Ui_MainWindow

import feedparser

class Main(QMainWindow):
    def __init__(self):
	    QMainWindow.__init__(self)
	    # Setup pyuic generated code
	    self.ui = Ui_MainWindow()
	    self.ui.setupUi(self)
	    ad = feedparser.parse("http://www.appuntidigitali.it/feed")
	    #Populate TreeWiget with elements
	    for entry in ad.entries:
	        item = QTreeWidgetItem([entry.title, entry.author, entry.slash_comments])
	        self.ui.treeWidget.addTopLevelItem(item)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window=Main()
    window.show()
    sys.exit(app.exec_())

Questo file (che io ho chiamato adreader.py) è il file principale del nostro progetto. Se avete qualche nome più evocativo (magari con una i davanti :P) potete semplicemente consigliarlo nei commenti.

Analizziamo adesso i punti salienti:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

La prima riga non è altro che uno Shebang che serve ad indicare al sistema operativo con quale interprete utilizzare per lo script lanciato. Con questo piccolo accorgimento è possibile lanciare il programma senza far riferimento in maniera esplicita all’interprete python ma richiamandolo come eseguibile. La seconda riga serve a dichiarare la codifica del file sorgente.
Sospetto che queste due righe non servano assolutamente a niente in ambiente windows poichè la prima è legata ad una caratteristica tipica dei sistemi unix e la codifica standard in casa MS non è utf-8.
Sotto segnalazione dell’attento Carlosh aggiungo che in realtà la dichiarazione della codifica è necessaria anche sotto windows per non incappare in errori di sintassi nel caso utilizzassimo caratteri accentati.

import sys
# Import Qt modules
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# Import pyuic4 compiled GUI
from mainwindowUi import Ui_MainWindow

import feedparser

Subito sotto vengono importati i vari moduli utilizzati all’interno del programma. Alla riga 6 viene importata la classe Ui_MainWindow ottenuta dalla compilazione del file ui con il tool pyuic4 descritto in precedenza.

Finita la parte di importazione dei moduli possiamo vedere la definizione della classe Main.

class Main(QMainWindow):
    def __init__(self):
	    QMainWindow.__init__(self)
	    # Setup pyuic generated code
	    self.ui = Ui_MainWindow()
	    self.ui.setupUi(self)

La nostra classe Main è una classe figlia di QMainWindow delle Qt. Come prima cosa  viene sovrascritto il costruttore (metodo __init__). All’interno del costruttore della nostra classe Main deve essere richiamato il costruttore di QMainWindow (classe genitrice) a cui passiamo il riferimento dell’attuale oggetto Main istanziato (self).

Subito dopo si eseguono due passi per l’integrazione del codice generato da pyuic nel nostro Main. Non spiegherò cosa avviene nello specifico ma se andate a leggere il codice del file prodotto da pyuic (mainwindowUi.py) potete farvi un idea più approfondita. Quello che basta sapere è che adesso possiamo accedere a tutti i widget composti in precedenza con il designer semplicemente riferendoci all’oggetto ui della classe Main.

A questo punto rimane solo da fare il parsing del feed e popolare il treeWidget con QTreeWidgetItem ad-hoc.

	    #Populate TreeWiget with elements
	    for entry in ad.entries:
	        item = QTreeWidgetItem([entry.title, entry.author, entry.slash_comments])
	        self.ui.treeWidget.addTopLevelItem(item)

Il codice è assolutamente triviale e non merita particolari spiegazioni.

Quello che rimane è il main del nostro programma:

if __name__ == "__main__":

La variabile __name__ in python contiene il namespace. Se un file sorgente viene importato come modulo il suo namespace corrisponde al nome del file. Se invece il file viene invocato direttamente il suo namespace sarà uguale a “__main__”.

L’istruzione condizionale fa in modo che la porzione di codice sottostante venga eseguita solo in caso di invocazione diretta del file e non nel caso di importazione.

    app = QApplication(sys.argv)
    window=Main()
    window.show()
    sys.exit(app.exec_())

Nelle quattro righe successive non si fa altro che creare una QApplication (sempre necessaria per le applicazioni che utilizzano le Qt), istanziare la classe Main appena scritta, mostrare a schermo la finestra principale ed attendere la chiusura dell’applicazione.

Con questi semplicissimi passi avete visto come si può creare in maniera rapida una piccola applicazione grafica. Nella prossima (e credo ultima) puntata vedremo come gestire gli eventi e come visualizzare un post in una webView.

10 Commenti »

I commenti inseriti dai lettori di AppuntiDigitali non sono oggetto di moderazione preventiva, ma solo di eventuale filtro antispam. Qualora si ravvisi un contenuto non consono (offensivo o diffamatorio) si prega di contattare l'amministrazione di Appunti Digitali all'indirizzo info@appuntidigitali.it, specificando quale sia il commento in oggetto.

  • # 1
    Roberto
     scrive: 

    Bell’articolo …
    Circa 2 mesi fa sono passato al python dal java ( principalmente per provare le pygame ) e ora sto convertendo tutti i vecchi progetti di java in python solo per il gusto di vedere di quanto si riducono ( in lunghezza xD ) .
    Devo dire che le pyqt mi affascinano parecchio …

  • # 2
    Matteo Rincanti
     scrive: 

    Ciao,
    anch’io stavo cercando di sviluppare una applicazione del genere sempre in python, però mi sono intoppato nel parser dell’html della pagina web.
    Anche te pensi di arrivare a questo punto?
    Hai già qualche idea/soluzione?
    Sto dicendo cavolate?

    Ciao, ciao

  • # 3
    Carlosh
     scrive: 

    Di nuovo complimenti per questo nuovo articolo e grazie della citazione per quello precedente. :)

    In questa nuova applicazione c’è parecchia carne al fuoco (per le mie competenze) e avrò parecchio da studiare (tempo permettendo)…
    Volevo solo segnalare una cosa riguardante la seconda riga di codice:

    # -*- coding: utf-8 -*-

    anche in ambiente windows risulta necessaria, altrimenti in fase di esecuzione, se ci sono ad esempio, dei commenti con lettere accentate si avrà un’errore del tipo:

    SyntaxError: Non-ASCII character ‘\xe8′ in file feed2.py on line 12, but no enco
    ding declared; see http://www.python.org/peps/pep-0263.html for details

    Nel nostro caso non sarebbe successo niente, in quanto non c’è nessun carettere “particolare” all’interno del sorgente, ma ho preferito riportarlo, più che altro per evitare che in futuro possa capitare a tutti quelli che come me sono alle prime armi…

    Alla prossima puntata…

  • # 4
    Emanuele Rampichini (Autore del post)
     scrive: 

    @Matteo Rincanati
    Ancora non ho pensato a come risolvere la cosa causa settimana di esami universitari. Quando inizierò a lavorare al prossimo articolo vedrò come affrontare il problema. Ho già alcune idee comunque.

    @Carlosh

    Di nuovo complimenti per questo nuovo articolo e grazie della citazione per quello precedente. :)

    Grazie a te per la condivisione dei problemi che hai riscontrato su windows. Anche in questo caso inserirò la tua esperienza nell’articolo. ;-)

    @Tutti
    Grazie per i complimenti.

  • # 5
    Ryuzaki_Eru
     scrive: 

    Quando vedo queste cose sono ancora più fiero di essere un Pythonista :D

  • # 6
    Daniele
     scrive: 

    Ciao,
    sarebbe possibile linkare il tuo tutorial sul nostro sito dedicato alle Qt?

  • # 7
    Emanuele Rampichini (Autore del post)
     scrive: 

    @Daniele
    Credo che non ci siano problemi se segui le linee guida:

    http://www.appuntidigitali.it/legali/

  • # 8
    Daniele
     scrive: 

    Perfetto, leggo che i post sono sotto creative commons. Comunque l’intenzione è quella di mettere il link direttamente alle lezioni qui su appunti digitali, non copiamo nulla, solo i 3 link alle rispettive lezioni.

  • # 9
    Daniel
     scrive: 

    Ottimi articoli, sono proprio quello che servono a un newbie per imparare un linguaggio!

    E da newbie ho subito un problema: il file .py che fai creare tramite pyuic4, dove và posizionato?
    Io lavoro su ubuntu LL..

    Inoltre, tu hai chiamato i file mainwindow.ui e mainwindowUi.py, ma nel programma importi la libreria Ui_MainWindow: è un nome generato automaticamente dalle pyQt in base al nome del file.ui che crei?
    Se si, quali linee guida segue il nome della libreria, e c’è un modo di saperlo (vorrei evitare di avere file con nome questo_file_e_un_mio_esempio_con_le_qt_4.ui e trovarmi la libreria con un nome altrettanto lungo ;)?

  • # 10
    Emanuele Rampichini (Autore del post)
     scrive: 

    Ciao Daniel.
    durante tutto il progetto i file .py sono tutti nella stessa directory.

    Il nome che importi viene generato direttamente da pyuic a partire da quello del top widgwet a cui hai dato il nome all’interno del designer (in questo caso io ho lasciato il default: “MainWindow”)
    Il nome del file .ui è del tutto indipendente da quello della classe da importare. La regola d’oro per i nomi di solito è: “dai nomi che siano significativi”. In questo caso essendo l’esempio particolarmente semplice mi sembra di non aver cambiato nemmeno uno dei nomi di default.
    Comunque se vuoi vedere come ho strutturato il codice finale puoi scaricarlo dal repo mercurial su cui ho hostato l’esempio.

    http://code.google.com/p/adreader/

Scrivi un commento!

Aggiungi il commento, oppure trackback dal tuo sito.

I commenti inseriti dai lettori di AppuntiDigitali non sono oggetto di moderazione preventiva, ma solo di eventuale filtro antispam. Qualora si ravvisi un contenuto non consono (offensivo o diffamatorio) si prega di contattare l'amministrazione di Appunti Digitali all'indirizzo info@appuntidigitali.it, specificando quale sia il commento in oggetto.