Introduzione all'uso di PyQt
per realizzare semplici interfacce grafiche
per i nostri programmi Python

Cosa sono Qt e PyQt

[Da Wikipedia]
In programmazione, Qt è una libreria multipiattaforma per lo sviluppo di programmi con interfaccia grafica tramite l'uso di widget (congegni o elementi grafici). Qt, ampiamente utilizzato nell'ambiente desktop KDE per Linux, è stato sviluppato dall'azienda Qt Software (meglio conosciuta come Trolltech o Quasar Technologies)...
Qt usa il linguaggio C++ standard [...] ma esistono interfacce per Java, Python, C, Perl e PHP. Gira sulle piattaforme principali...
[Fine citazione]

PyQt è dunque l'interfaccia Python di Qt. Di fatto, PyQt è solo un wrapper verso le procedure Qt scritte in C++; questo si vede molto bene nella documentazione delle classi, che spesso non è stata neppure adattata a Python, ma conserva impostazione e soprattutto esempi presi dal Qt in C++ ; vedi per esempio la documentazione della classe QVBoxLayout WEB.

Impostazione

Dopo un brevissimo riepilogo di alcuni concetti generali, per il resto questa introduzione si dipanerà attraverso la presentazione e la discussione di alcuni esempi.
I sorgenti verranno copiati da questa pagina Web in un editor di testo (o in Idle), eventualmente modificati e lanciati in esecuzione.

Risorse

Non è chiaro se il libro di Summerfield sia di pubblico dominio oppure no; per un po' di tempo è stato scaricabile anche da Google, ma adesso non lo è più: vedi qui.

Curiosità

La parola widget origina dalla contrazione dei termini window e gadget.
Qt ha radici molto antiche; alcuni widget (vedi QLCDNumber, WEB) provengono addirittura dal Basic del Sinclair ZX Spectrum (1982: WEB).

Aspetti generali

Programmazione ad eventi (event-driven)

Qt / PyQt, come (credo) tutte le librerie per lo sviluppo di interfacce grafiche, si basa su un paradigma di programmazione ad eventi. Concepire i propri programmi per una modalità di funzionamento ad eventi rappresenta probabilmente una delle maggiori difficoltà concettuali che si incontrano per passare da una programmazione a linea di comando ad una programmazione controllata da una interfaccia grafica.

Programmazione sequenziale Programmazione ad eventi
Mentre in un programma tradizionale l'esecuzione delle istruzioni segue percorsi fissi, che si ramificano soltanto in punti ben determinati predefiniti dal programmatore, nei programmi scritti utilizzando la tecnica a eventi il flusso del programma è largamente determinato dal verificarsi di eventi esterni.
I programmi che utilizzano la programmazione a eventi (denominati spesso programmi event-driven) sono composti tipicamente da diversi brevi sotto-programmi, chiamati gestori degli eventi (event handlers) - che sono eseguiti in risposta agli eventi esterni.

OOP: Genitori, figli, proprietari e posseduti

La programmazione ad eventi si avvale in modo sostanziale dell'architettura offerta dalla programmazione ad oggetti.
Per seguire senza troppe difficoltà questa introduzione a PyQt, sarebbe bene quindi avere ben chiari i concetti base della OOP e in particolare i concetti di: classe, istanza, ereditarietà, metodo, proprietà.

È importante capire bene (e soprattutto non confondere) la relazione genitore-figlio relativa alle classi e quella proprietario-posseduto relativa agli oggetti istanziati. La documentazione usa il termine parent in entrambi i casi; nel secondo caso secondo me sarebbe preferibile utilizzare il termine owner e mi sforzerò di farlo.

Ciò detto, iniziamo!

Ricorda:

Le applicazioni basate su una dialog-box costituiscono una classe di applicazioni semplici ma versatili, che permettono di soddisfare una grande quantità di esigenze. La loro principale limitazione consiste nell'impossibilità di inserire un sistema di menù a tendina e quindi nel dover associare tutte le funzionalità a pulsanti ed altri widget inseribili in una dialog box.

Esempio 1: una finestra di dialogo vuota e un pulsante

Notare:

Ricorda:

Esempio 2: lo scheletro di una applicazione a dialog-box

Notare:

Esempio 3: check box con allineamento verticale

Notare:

Esempio 4: radio button con allineamento orizzontale

Notare:

Ricorda:

Layout semplice
  1. Creo i widget, che appartengono tutti alla dialog-box principale.
  2. Inizializzo un layout senza proprietario.
  3. Assegno i widget al layout con layoutName.addWidget(widgetName).
  4. Assegno il layout alla dialog-box principale con self.setLayout(layoutName).

Esempio 5: doppio set di radio button (indipendenti)

Notare:

Ricorda:

Layout annidati (due in un terzo)
  1. Creo i widget, che appartengono tutti alla dialog-box principale.
  2. Inizializzo un primo layout senza proprietario.
  3. Assegno alcuni widget al layout con layoutName.addWidget(widgetName).
  4. Inizializzo un secondo layout senza proprietario.
  5. Assegno altri widget al layout con layoutName.addWidget(widgetName).
  6. Inizializzo un terzo layout senza proprietario.
  7. Assegno i layout precedenti a questo terzo layout con terzoLayoutName.addLayout(layoutName).
  8. Posso assegnare a questo terzo layout anche alcuni widget con terzoLayoutName.addWidget(widgetName).
  9. Assegno il terzo layout alla dialog-box principale con self.setLayout(terzoLayoutName).

Esempio 6: doppio set di radio button indipendenti (approccio diverso)

Notare:

Ricorda:

Layout con gruppi
  1. Creo i gruppi QGroupBox, che appartengono alla dialog-box principale; ricordare che si tratta di widget!
  2. Creo gli altri widget, che appartengono ai vari group box.
  3. Per ogni group box:
    1. inizializzo un layout senza proprietario;.
    2. assegno i widget del gruppo al layout con layoutName.addWidget(widgetName);.
    3. assegno il layout al gruppo con groupboxName.setLayout(layoutName).
  4. Inizializzo un layout senza proprietario.
  5. Assegno i gruppi al layout con layoutName.addWidget(groupboxName).
  6. Assegno altri eventuali widget (fuori dai gruppi: questi widget appartengono alla dialog-box principale) al layout con layoutName.addWidget(widgetName).
  7. Assegno quest'ultimo layout alla dialog-box principale con self.setLayout(layoutName).

Esempio 7: altra composizione di layout e prime funzionalità

Notare:

Esempio 8: altri widget di uso comune; layout a griglia; altre funzionalità

Notare:

Ricorda:

Per assegnare i widget ad un layout a griglia la sintassi completa è gridlayoutName.addWidget(widgetName,row,col,rowspan,colspan).

Riassunto della puntata precedente


Esempio 9: potenziometri e display LCD

Notare:

Esempio 10: potenziometri e colori

Notare:

Ricorda:

Qt e le immagini
Qt provides four classes for handling image data: QImage, QPixmap, QBitmap and QPicture. QImage is designed and optimized for I/O, and for direct pixel access and manipulation, while QPixmap is designed and optimized for showing images on screen. QBitmap is only a convenience class that inherits QPixmap, ensuring a depth of 1. Finally, the QPicture class is a paint device that records and replays QPainter commands.

Esempio 11: file open dialog-box, lettura e visualizzazione di immagini, dialog-box secondarie modali e non modali, message box

Notare:

Ricorda:

dialog-box speciali

Alcue dialog-box specializzate

dialog-box secondarie

Esempio 12: lettura e visualizzazione di file di testo e HTML

Notare:

Ricorda:

Il widget QTextEdit può essere utilizzato anche per l'input e l'editing di testo. Per l'input e l'editing di testo su linea singola esiste anche il widget QLineEdit.

Esempio 13: visualizzazione di un grafico Pyplot

Notare:

Esempio 14: visualizzazione di un grafico Pyplot con blocco e sblocco

Notare:

Esempio 15: visualizzazione di due grafici in due figure Pyplot con blocco e sblocco

Notare:

Esempio 16: visualizzazione di un grafico Pyplot in una dialog-box PyQt

Notare:

Esempio 17: lo scheletro di una applicazione a finestra (window)

Notare:

Esempio 18: operazioni su immagini (esempio di applicazione a finestra e menù)

Notare:


Che altro ancora?


Ritorna alla pagina indice

Daniele Andreuccetti, IFAC-CNR, giugno 2015