Dimensione: 14258
Commento:
|
Dimensione: 36506
Commento:
|
Le cancellazioni sono segnalate in questo modo. | Le aggiunte sono segnalate in questo modo. |
Linea 8: | Linea 8: |
<<Informazioni(forum="https://forum.ubuntu-it.org/viewtopic.php?f=46&t=638223"; rilasci="18.04 16.04 14.04")>> | <<Informazioni(forum="https://forum.ubuntu-it.org/viewtopic.php?f=46&t=638223"; rilasci="18.04 20.04 22.04")>> |
Linea 12: | Linea 12: |
All'interno di questa pagina sono presenti degli esempi di come creare delle semplici interfacce grafiche usando programmi come '''wxPython''', '''Tkinter''' e '''PyGTK'''. '''Tkinter''' è di norma preinstallato in '''Ubuntu''', mentre '''wxPython''' può essere installato con: {{{ sudo apt install python3-wxgtk4.0 }}} * tutto ciò che viene scritto preceduto dal carattere # è considerato dall'interprete come un commento. * questi esempi sono scritti per l'interprete '''Python 3.x''' per la guida nella precedente versione '''Python 2.7.xx''', vedi [[Programmazione/Python/InterfacceGrafiche| InterfacceGrafiche]] = PyGTK = '''GTK+''' è un toolkit per la creazione di interfacce grafiche è stato progettato inizialmente come ausilio alla programmazione per [[Grafica/Gimp|GIMP]] ed è diventato una parte fondamentale dell'ambiente [[AmbienteGrafico/Gnome| GNOME]]. '''PyGTK''' è un set di moduli che permettono l'interfacciamento tra '''Python''' e le librerie '''GTK''', è un toolkit orientato agli oggetti, permette quindi la possibilità di riutilizzare dello stesso codice in più applicazioni. |
Questa pagina presenta alcuni esempi su come creare con Python programmi dotati di una semplice interfaccia grafica usando uno dei moduli '''GTK''', '''!PyQt''', '''tkinter''' o '''wxPython''' che si appoggiano tutti a librerie Open Source e multipiattaforma.<<BR>> In ciascuno di questi esempi viene realizzata una versione grafica di ''!AreaTriangolo_con_eccezioni.py'', script presente all'interno di [[Programmazione/Python/ListatiPython3#Listato_3| questa pagina]]<<BR>> Poiché tutti i moduli citati e le loro librerie usano la programmazione orientata agli oggetti, è possibile riutilizzare in maniera modulare lo stesso codice in più applicazioni riducendo tempo e risorse per lo sviluppo. ## * questi esempi sono scritti per l'interprete '''Python 3.x''' per la guida nella precedente versione '''Python 2.7.xx''', vedi [[Programmazione/Python/InterfacceGrafiche| InterfacceGrafiche]] = GTK = '''GTK+''' è un toolkit per la creazione di interfacce grafiche che è stato progettato inizialmente come ausilio alla programmazione per [[Grafica/Gimp|GIMP]] ed è diventato una parte fondamentale dell'ambiente [[AmbienteGrafico/Gnome| GNOME]].<<BR>> Il programma è preinstallato in '''Ubuntu'''. Nel caso fosse stato inavvertitamente rimosso o mancasse [[AmministrazioneSistema/InstallareProgrammi|installare]] il pacchetto [[apt://python3-gi|python3-gi]]. ##Il pacchetto fornisce il modulo '''gi''' il quale provvede ai collegamenti '''Python3''' alle librerie '''GTK+''' versione 3 e seguenti. ##'''PyGTK''' è un set di moduli che permettono l'interfacciamento tra '''Python''' e le librerie '''GTK+''', è un toolkit orientato agli oggetti, permette quindi la possibilità di riutilizzare dello stesso codice in più applicazioni. === Esempio di applicazione === |
Linea 29: | Linea 30: |
#!/usr/bin/python3 |
|
Linea 31: | Linea 34: |
from gi.repository import Gtk from math import sqrt |
from gi.repository import Gtk # Importa il modulo per l'interfaccia grafica from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math class TriangoloImpossibile(Exception): """Classe per sollevare un'eccezione se vengono immesse misure incompatibili.""" def __init__(self, message="Un triangolo con questi lati non esiste."): self.message = message |
Linea 35: | Linea 45: |
a, b, c = 0, 0, 0 # Metodo costruttore, in python i costruttori hanno il nome speciale __init__ def __init__(self,a,b,c): # Controlliamo se i tre valori dati possono effettivamente #essere le misure dei lati di un triangolo. # Caso contrario solleviamo una bella eccezione! if ((a+b>c) and (a+c>b) and (b+c>a)): self.a=a self.b=b self.c=c else: raise "TriangoloImpossibile"("I lati non possono formare un triangolo") # abbiamo dato un nome ed un essaggio di errore all'eccezione # Metodo che calcola il perimetro |
"""Classe per costruire e validare gli oggetti triangolo da calcolare. Oltre al costruttore, la classe ha due metodi: un metodo che calcola il perimetro e uno che calcola l'area. Attributi della classe sono le misure dei tre lati a, b, c """ def __init__(self, a, b, c): """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__ Controlla se i tre valori immessi sono accettabili, cioè se sono validi come misure dei lati di un triangolo. In caso contrario solleva una eccezione TriangoloImpossibile. """ if a + b > c and a + c > b and b + c > a: self.a = a self.b = b self.c = c else: raise TriangoloImpossibile |
Linea 51: | Linea 67: |
"""Calcola il perimetro. Ritorna un numero in virgola mobile.""" | |
Linea 53: | Linea 70: |
# Metodo che calcola l'area (tramite formula di Erone) | |
Linea 55: | Linea 71: |
p=self.perimetro()/2.0 return sqrt(p*(p-self.a)*(p-self.b)*(p-self.c)) |
"""Calcola l'area con la formula di Erone. Ritorna un numero in virgola mobile.""" p = self.perimetro() / 2 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c)) |
Linea 59: | Linea 77: |
"""Classe che definisce l'interfaccia grafica.""" |
|
Linea 60: | Linea 80: |
Gtk.Window.__init__(self, title = "Calcolo area triangolo") |
Gtk.Window.__init__(self, title="Calcolo area triangolo") |
Linea 66: | Linea 86: |
self.label1 = Gtk.Label(label = "Lato 1 ") self.label2 = Gtk.Label(label = "Lato 2 ") self.label3 = Gtk.Label(label = "Lato 3 ") |
self.label1 = Gtk.Label(label="Lato 1 ") self.label2 = Gtk.Label(label="Lato 2 ") self.label3 = Gtk.Label(label="Lato 3 ") |
Linea 74: | Linea 93: |
self.button = Gtk.Button(label = "Calcola") | self.button = Gtk.Button(label="Calcola") |
Linea 76: | Linea 95: |
self.risultato = Gtk.Label(" -- ") | self.risultato = Gtk.Label(label=" -- ") |
Linea 84: | Linea 103: |
Linea 87: | Linea 106: |
self.colonna.pack_start(self.riga3, True, True, 7) | self.colonna.pack_start(self.riga3, True, True, 7) |
Linea 92: | Linea 111: |
Linea 96: | Linea 112: |
try: a = float(self.entry1.get_text()) # legge i dati inseriti nella 1 casella |
"""Acquisisce l'input, lo valida e calcola l'area.""" try: # Legge i dati inseriti in ogni casella. a = float(self.entry1.get_text()) |
Linea 101: | Linea 118: |
self.risultato.set_text(str(triangolo.area())) except ValueError: # catturo l'eccezione |
except ValueError: # Cattura l'errore di tipo di dati. |
Linea 104: | Linea 120: |
except "TriangoloImpossibile": # catturo la seconda eccezione self.risultato.set_text("I lati immessi non possono formare un triangolo") |
except TriangoloImpossibile as err: # Cattura l'errore di dati non possibili. self.risultato.set_text(err.message) else: # Nessun errore, espone il risultato. self.risultato.set_text(f"Area = {triangolo.area()}") |
Linea 115: | Linea 131: |
}}} = Tkinter = '''Tk''' è un piccolo toolkit per la creazione di interfacce grafiche è stato successivamente portato anche verso altri linguaggi come '''Python''', '''Ruby''', '''Lisp''', ecc.. '''Tkinter''' è il modulo '''Python''' che permette l'interfacciamento con '''Tk'''. == Esempio di applicazione == Di seguito viene mostrato un esempio di programma: |
}}} = PyQt = '''[[https://it.wikipedia.org/wiki/Qt_(toolkit)|Qt]]''' è un insieme di librerie usate per fornire di interfaccia grafica applicazioni e ambienti desktop (è tra l'altro parte integrante dell'ambiente grafico [[AmbienteGrafico/Kde| KDE Plasma]]). {{{#!wiki important Per la serie 5 delle librerie Qt il supporto cesserà a maggio 2023. È consigliato usare per i nuovi progetti la versione 6. }}} == Installazione == === Pacchetto deb === Per usare le librerie nella versione Qt5 [[AmministrazioneSistema/InstallareProgrammi|installare]] il pacchetto [[apt://python3-pyqt5|python3-pyqt5]]. Per usare le librerie nella versione '''Qt6''' da '''Ubuntu 22.10''' e successivi [[AmministrazioneSistema/InstallareProgrammi|installare]] il pacchetto [[apt://python3-pyqt6|python3-pyqt6]]. {{{#!wiki note Fino a '''Ubuntu 22.04''' la versione 6 della suite di pacchetti '''Python3-Py``Qt6''' non è disponibile nei [[Repository|repository]] ufficiali. }}} In alternativa possono essere installati tramite il [[https://launchpad.net/~savoury1/+archive/ubuntu/qt-6-2|PPA Qt 6.2.x - backports]], che fornisce sia versioni più recenti delle [[https://it.wikipedia.org/wiki/Qt_(toolkit)|librerie Qt6]] rispetto a quelle del repository ufficiale, sia la suite di pacchetti '''Python3-Py``Qt6''' fino a '''Ubuntu 22.04'''. 0. Digitare nel [[AmministrazioneSistema/Terminale|terminale]] il comando:{{{ sudo add-apt-repository ppa:savoury1/qt-6-2 }}} 0. Aggiornare il database dei pacchetti:{{{ sudo apt update }}} 0. [[AmministrazioneSistema/InstallareProgrammi|Installare]] il pacchetto [[apt://python3-pyqt6|python3-pyqt6]]. === Tramite pip === 0. [[AmministrazioneSistema/InstallareProgrammi|installare]] il pacchetto [[apt://python3-pip|pip3]]. 0. Digitare nel [[AmministrazioneSistema/Terminale|terminale]], in funzione della versione scelta, uno dei seguenti comandi: {{{ pip3 install pyQt5 }}} o {{{ pip3 install pyQt6 }}} === Esempio di applicazione === {{{#!python #!/usr/bin/env python3 # -*- coding: utf-8 -*- from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math import sys # NB questo script può funzionare sia con le PyQt6 che con le PyQt5. # Nel secondo caso bisogna sostituire nelle tre righe seguenti `PyQt6' con: `PyQt5' from PyQt6.QtCore import Qt from PyQt6 import QtGui from PyQt6.QtWidgets import (QApplication, QDialog, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QSizePolicy, QVBoxLayout ) class Ui_Dialog(object): """Classe che crea il widget contenitore di tutta l'nterfaccia grafica""" def setupUi(self, Dialog): Dialog.resize(300, 200) Dialog.setWindowTitle("Calcolo area triangolo") self.verticalLayout = QVBoxLayout(Dialog) self.gridLayout = QGridLayout() self.label_lato1 = QLabel() self.label_lato1.setText("Lato 1") self.input_lato1 = QLineEdit() self.gridLayout.addWidget(self.label_lato1, 0, 0, 1, 1) self.gridLayout.addWidget(self.input_lato1, 0, 1, 1, 1) self.label_lato2 = QLabel() self.label_lato2.setText("Lato 2") self.input_lato2 = QLineEdit() self.gridLayout.addWidget(self.label_lato2, 1, 0, 1, 1) self.gridLayout.addWidget(self.input_lato2, 1, 1, 1, 1) self.label_lato3 = QLabel() self.label_lato3.setText("Lato 3") self.input_lato3 = QLineEdit() self.gridLayout.addWidget(self.label_lato3, 2, 0, 1, 1) self.gridLayout.addWidget(self.input_lato3, 2, 1, 1, 1) self.verticalLayout.addLayout(self.gridLayout) self.esito = QLabel() sizePolicy = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.esito.sizePolicy().hasHeightForWidth()) self.esito.setSizePolicy(sizePolicy) self.esito.setAlignment(Qt.AlignmentFlag.AlignCenter) self.esito.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) self.esito.setCursor(QtGui.QCursor(Qt.CursorShape.IBeamCursor)) font = QtGui.QFont() font.setPointSize(12) font.setBold(True) font.setWeight(75) self.esito.setFont(font) self.esito.setTextFormat(Qt.TextFormat.RichText) self.esito.setWordWrap(False) self.esito.setText(". . .") self.esito_HLayout = QHBoxLayout() self.esito_HLayout.addWidget(self.esito, Qt.AlignmentFlag.AlignCenter) self.verticalLayout.addLayout(self.esito_HLayout) self.button_horizontalLayout = QHBoxLayout() self.button_ok = QPushButton("Calcola") self.button_ok.setFixedSize(80,40) self.button_horizontalLayout.addWidget(self.button_ok, Qt.AlignmentFlag.AlignCenter) self.verticalLayout.addLayout(self.button_horizontalLayout) self.button_ok.clicked.connect(self.OK) def OK(self): self.esito.setText(self.calcoli()) def calcoli(self): """Acquisisce l'input, lo valida e calcola l'area.""" try: # Legge i dati inseriti in ogni casella. a = float(self.input_lato1.text()) b = float(self.input_lato2.text()) c = float(self.input_lato3.text()) triangolo = Triangolo(a, b, c) except ValueError: # Cattura l'errore di tipo di dati. risultato = "Devi inserire valori numerici." except TriangoloImpossibile as err: # Cattura l'errore di dati non possibili. risultato = err.message else: # Nessun errore, espone il risultato. risultato = f"Area = {triangolo.area()}" return risultato class TriangoloImpossibile(Exception): """Classe per sollevare un'eccezione se vengono immesse misure incompatibili.""" def __init__(self, message="Un triangolo con questi lati non esiste."): self.message = message class Triangolo: """Classe per costruire e validare gli oggetti triangolo da calcolare. Oltre al costruttore, la classe ha due metodi: un metodo che calcola il perimetro e uno che calcola l'area. Attributi della classe sono le misure dei tre lati a, b, c """ def __init__(self, a, b, c): """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__ Controlla se i tre valori immessi sono accettabili, cioè se sono validi come misure dei lati di un triangolo. In caso contrario solleva l'eccezione TriangoloImpossibile. """ if a + b > c and a + c > b and b + c > a: self.a = a self.b = b self.c = c else: raise TriangoloImpossibile def perimetro(self): """Calcola il perimetro. Ritorna un numero in virgola mobile.""" return self.a + self.b + self.c def area(self): """Calcola l'area con la formula di Erone. Ritorna un numero in virgola mobile.""" p = self.perimetro() / 2 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c)) if __name__ == "__main__": import sys app = QApplication(sys.argv) Dialog = QDialog() ui = Ui_Dialog() ui.setupUi(Dialog) Dialog.show() sys.exit(app.exec()) }}} === Un esempio più avanzato della stessa applicazione === {{{#!wiki note Questo script funziona solo con Qt6.}}} |
Linea 127: | Linea 327: |
# Importiamo la funzione sqrt (radice quadrata) dal modulo math from math import sqrt # Importiamo i widgets dal modulo Tkinter from tkinter import * # Definiamo una classe Triangolo con tre metodi: # un costruttore, un metodo che calcola il perimetro e uno che calcola l'area del triangolo. |
# -*- coding: utf-8 -*- from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math import sys from PyQt6 import QtCore, QtGui from PyQt6.QtWidgets import (QApplication, QDialog, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QVBoxLayout ) INTESTAZIONE = {'input': "Inserire le misure", 'error': "Errore", 'end': "" } class Ui_Dialog(object): """Classe che crea il widget contenitore di tutta l'nterfaccia grafica""" def setupUi(self, Dialog): Dialog.resize(400, 250) Dialog.setWindowTitle("Calcolo dell'area di un triangolo") #icon = QtGui.QIcon('/percorso/di/una/icona.svg') #Dialog.setWindowIcon(icon) self.verticalLayout = QVBoxLayout(Dialog) self.gridLayout = QGridLayout() self.intestazione = QLabel(Dialog) font = QtGui.QFont() font.setPointSize(12) font.setBold(True) font.setWeight(75) self.intestazione.setFont(font) self.intestazione.setTextFormat(QtCore.Qt.TextFormat.RichText) self.intestazione.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.intestazione.setText(INTESTAZIONE['input']) self.intestazione.default_ss = self.intestazione.styleSheet() # salva lo styleSheet originale self.verticalLayout.addWidget(self.intestazione) self.label_lato1 = QLabel() self.label_lato1.setText("Lato 1") self.input_lato1 = MyLineEdit("1") self.gridLayout.addWidget(self.input_lato1, 0, 0, 1, 1) self.gridLayout.addWidget(self.label_lato1, 0, 1, 1, 1) self.label_lato2 = QLabel() self.label_lato2.setText("Lato 2") self.input_lato2 = MyLineEdit("2") self.gridLayout.addWidget(self.input_lato2, 1, 0, 1, 1) self.gridLayout.addWidget(self.label_lato2, 1, 1, 1, 1) self.label_lato3 = QLabel() self.label_lato3.setText("Lato 3") self.input_lato3 = MyLineEdit("3") self.gridLayout.addWidget(self.input_lato3, 2, 0, 1, 1) self.gridLayout.addWidget(self.label_lato3, 2, 1, 1, 1) self.verticalLayout.addLayout(self.gridLayout) self.messaggio = QLabel(Dialog) self.messaggio.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.messaggio.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.IBeamCursor)) font = QtGui.QFont() font.setPointSize(12) font.setBold(True) font.setWeight(75) self.messaggio.setFont(font) self.messaggio.setTextFormat(QtCore.Qt.TextFormat.RichText) self.messaggio.setWordWrap(False) self.messaggio.setText("") self.horizontalLayout_messaggio = QHBoxLayout() self.horizontalLayout_messaggio.addWidget(self.messaggio, QtCore.Qt.AlignmentFlag.AlignLeft) self.gridLayout.addLayout(self.horizontalLayout_messaggio, 3, 0, 1, 2) self.button_ok = QPushButton("Calcola") self.button_ok.setEnabled(False) self.button_ok.setFixedSize(80,40) self.button_cancel = QPushButton("Annulla") self.button_cancel.setFixedSize(80,40) self.button_cancel.setStyleSheet("QToolTip {background-color: #ffffbb; \ color: black; \ font: 9pt; \ border-radius: 3px}" ) self.button_cancel.setToolTip("Per uscire") self.horizontalLayout_buttons = QHBoxLayout() self.horizontalLayout_buttons.addWidget(self.button_ok, QtCore.Qt.AlignmentFlag.AlignRight ) self.horizontalLayout_buttons.addWidget(self.button_cancel, QtCore.Qt.AlignmentFlag.AlignRight ) self.gridLayout.addLayout(self.horizontalLayout_buttons, 4, 1, 1, 1) self.button_ok.clicked.connect(self.OK) self.button_cancel.clicked.connect(Dialog.reject) Dialog.setTabOrder(self.input_lato1, self.input_lato2) Dialog.setTabOrder(self.input_lato2, self.input_lato3) Dialog.setTabOrder(self.input_lato3, self.button_ok) Dialog.setTabOrder(self.button_ok, self.button_cancel) def check(self): """Viene eseguito da validazione() di ogni campo se ha input valido. Se tutti i campi sono validi, abilita il pulsante "Calcola". """ for campo in [self.input_lato1, self.input_lato2, self.input_lato3]: is_valid = getattr(campo, 'isValid') if not is_valid: break if is_valid: self.button_ok.setEnabled(True) def OK(self): self.messaggio.setText(self.calcoli()) def calcoli(self) -> str: """Acquisisce l'input, lo valida e restituisce l'area. Viene eseguito quando viene cliccato il pulsante "Calcola". Legge i dati da ogni campo e cambia il formato da it_IT.UTF-8 a C per potere convertire le stringhe in numero a virgola mobile con float(). Il formato del risultato viene restituito in it_IT.UTF-8 """ # a = float(self.input_lato1.text().replace('.', '').replace(',', '.')) b = float(self.input_lato2.text().replace('.', '').replace(',', '.')) c = float(self.input_lato3.text().replace('.', '').replace(',', '.')) try: triangolo = Triangolo(a, b, c) except TriangoloImpossibile as err: # Errore di dati incompatibili. risultato = err.message self.set_error_format() else: risultato = f"Area = {triangolo.area():.5g}".replace('.', ',') self.intestazione.setText(INTESTAZIONE['end']) return risultato def set_error_format(self): """Formatta e compila Intestazione e Risultato in caso di errore.""" self.intestazione.setStyleSheet("color: red") self.intestazione.setText(INTESTAZIONE['error']) self.messaggio.setStyleSheet("color: red") class TriangoloImpossibile(Exception): """Classe per sollevare un'eccezione se vengono immesse misure incompatibili.""" def __init__(self, message="Un triangolo con questi lati non esiste."): self.message = message |
Linea 136: | Linea 483: |
# Attributi della classe (le misure dei tre lati) a, b, c = 0, 0, 0 # Metodo costruttore def __init__(self,a,b,c): # Controlliamo se i tre valori dati possono effettivamente essere le misure dei lati di un triangolo. # Caso contrario solleviamo una bella eccezione! if ((a+b>c) and (a+c>b) and (b+c>a)): self.a=a self.b=b self.c=c else: # abbiamo dato un nome ed un essaggio di errore all'eccezione raise "TriangoloImpossibile"("I lati non possono formare un triangolo") # Metodo che calcola il perimetro def perimetro(self): return self.a + self.b + self.c # Metodo che calcola l'area (tramite formula di Erone) def area(self): p=self.perimetro()/2.0 return sqrt(p*(p-self.a)*(p-self.b)*(p-self.c)) # questa e' la classe che definisce l'interfaccia grafica |
"""Classe per costruire e validare l'oggetto triangolo da calcolare. Oltre al costruttore, la classe ha due metodi: un metodo che calcola il perimetro e uno che calcola l'area. Attributi della classe sono le misure dei tre lati a, b, c """ def __init__(self, a, b, c): """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__ Controlla se i tre valori immessi sono accettabili, cioè se sono validi come misure dei lati di un triangolo. In caso contrario solleva una eccezione TriangoloImpossibile. """ if a + b > c and a + c > b and b + c > a: self.a, self.b, self.c = a, b, c else: raise TriangoloImpossibile def perimetro(self) -> float: """Calcola il perimetro.""" return self.a + self.b + self.c def area(self) -> float: """Calcola l'area con la formula di Erone.""" p = self.perimetro() / 2 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c)) class MyLineEdit(QLineEdit): """Classe per istanziare i campi di input dei lati. Il campo viene formattato durante la scrittura in base all'input digitato: ha una maschera di input che accetta solo interi o decimali >= 0,00001 L'input è giudicato valido in base al formato numerico locale: n.nnn,nnnnn Per informare di questo, un tooltip compare passando il cursore sul campo. """ def __init__(self, *args): super(MyLineEdit, self).__init__() self.setStyleSheet("QToolTip {background-color: #ffffbb; \ color: black; \ font: 9pt; \ border-radius: 3px}" ) self.tooltip = "Usare la virgola come<br>separatore decimale" self.setToolTip(self.tooltip) self.default_ss = self.styleSheet() # salva lo styleSheet originale self.bg_colors = {'green': '#b6ffb5', 'yellow': '#ffff7d'} for arg in args: self.myLabel = getattr(ui, f"label_lato{arg}") # serve per la formattazione self.setPlaceholderText(f"Misura del {arg}° lato...") self.textChanged.connect(self.validazione) self.isValid = False # in partenza è vuoto ## validatore self.validator = QtGui.QDoubleValidator(bottom=0.00001, decimals=5) self.validator.setNotation(QtGui.QDoubleValidator.Notation.StandardNotation) self.setValidator(self.validator) def focusOutEvent(self, event): """Modifica la formattazione ogni volta che il campo perde il focus.""" super(MyLineEdit, self).focusOutEvent(event) state = self.validazione() if state is self.validator.State.Acceptable: # 2 self.default_format() else: self.invalid_format() def validazione(self): """Verifica se l'input del campo è valido o meno. Si basa sul validatore QDoubleValidator che è anche maschera di input e cioè impedisce l'immissione di caratteri non validi. Ma siccome si può cambiare campo con qualsiasi contenuto, anche non valid, comunque ritorna se la riga è valid o meno, per potere evidenziare l'errore. """ state = self.validator.validate(self.text(), 0)[0] if state is self.validator.State.Acceptable: # 2 self.isValid = True ui.check() bg_color = self.bg_colors['green'] elif state is self.validator.State.Intermediate: # 1 self.isValid = False bg_color = self.bg_colors['yellow'] self.setStyleSheet(self.default_ss + 'QLineEdit {color: black; \ background-color: %s \ }' %bg_color ) return state def default_format(self): """Ripristina lo styleSheet originale per segnalare input valido. Viene eseguito all'uscita dal campo. """ self.setStyleSheet(self.default_ss) self.myLabel.setStyleSheet(self.default_ss) def invalid_format(self): """Formatta il campo e l'etichetta per segnalare input non valido. Viene eseguito all'uscita dal campo. """ self.setStyleSheet(self.default_ss + "QLineEdit {border: 1px solid red}") self.myLabel.setStyleSheet("color: red") ui.button_ok.setEnabled(False) def focusInEvent(self, event): """Ripristina lo styleSheet originale quando si torna sul campo.""" super(MyLineEdit, self).focusInEvent(event) self.isValid = False ui.intestazione.setStyleSheet(self.default_ss) ui.intestazione.setText(INTESTAZIONE['input']) ui.messaggio.setStyleSheet(self.default_ss) ui.messaggio.setText("") self.default_format() if __name__ == "__main__": import sys app = QApplication(sys.argv) Dialog = QDialog() ui = Ui_Dialog() ui.setupUi(Dialog) Dialog.show() sys.exit(app.exec()) }}} = Tkinter = '''Tk''' è un piccolo toolkit per la creazione di interfacce grafiche che oltre a '''Python''' è stato portato anche verso altri linguaggi come '''Ruby''', '''Lisp''' etc. Per usare il programma [[AmministrazioneSistema/InstallareProgrammi|installare]] il pacchetto [[apt://python3-tk|python3-tk]]. ##Il pacchetto fornisce il modulo '''tkinter''' il quale permette l'interfacciamento di '''Python''' con '''Tk'''. === Esempio di applicazione === {{{#!python #!/usr/bin/python3 from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math # Importa widgets e altri attributi dal modulo per l'interfaccia grafica from tkinter import Button, Entry, Frame, Label, StringVar, E, W, N, S class TriangoloImpossibile(Exception): """Classe per sollevare un'eccezione se vengono immesse misure incompatibili.""" def __init__(self, message="Un triangolo con questi lati non esiste."): self.message = message class Triangolo: """Classe per costruire e validare gli oggetti triangolo da calcolare. Oltre al costruttore, la classe ha due metodi: un metodo che calcola il perimetro e uno che calcola l'area. Attributi della classe sono le misure dei tre lati a, b, c """ def __init__(self, a, b, c): """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__ Controlla se i tre valori immessi sono accettabili, cioè se sono validi come misure dei lati di un triangolo. In caso contrario solleva una eccezione TriangoloImpossibile. """ if a + b > c and a + c > b and b + c > a: self.a = a self.b = b self.c = c else: raise TriangoloImpossibile def perimetro(self): """Calcola il perimetro. Ritorna un numero in virgola mobile.""" return self.a + self.b + self.c def area(self): """Calcola l'area con la formula di Erone. Ritorna un numero in virgola mobile.""" p = self.perimetro() / 2 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c)) |
Linea 164: | Linea 676: |
def __init__(self): |
"""Classe che gestisce l'interfaccia grafica ed esegue i calcoli.""" def __init__(self): |
Linea 168: | Linea 681: |
self.master.minsize(250,150) # Dimensioni minime della finestra | self.master.minsize(250, 150) # Dimensioni minime della finestra |
Linea 171: | Linea 684: |
self.ris=StringVar() # Questa variabile stringa viene usata per self.ris.set("---") # aggiornare la gui quando il risultato cambia. # Rendiamo ridimensionabile la finestra dell'applicazione top=self.winfo_toplevel() |
self.ris = StringVar() # Questa variabile stringa viene usata per self.ris.set("---") # aggiornare la gui quando il risultato cambia. # Rende ridimensionabile la finestra dell'applicazione top = self.winfo_toplevel() |
Linea 179: | Linea 692: |
for i in range(5): self.rowconfigure(i, weight=1) | for i in range(5): self.rowconfigure(i, weight=1) |
Linea 182: | Linea 696: |
self.etichetta1=Label(self, text="Lato 1 ") # Etichetta del lato 1 self.etichetta1.grid(row=0, column=0, padx=2) self.entrata1=Entry(self) # Casella d'inserimento del lato 1 |
# Etichetta e casella di input del lato 1 self.etichetta1 = Label(self, text="Lato 1 ") self.etichetta1.grid(row=0, column=0, padx=2) self.entrata1 = Entry(self) |
Linea 189: | Linea 702: |
self.etichetta2=Label(self, text="Lato 2 ") # Etichetta del lato 2 | # Etichetta e casella d'inserimento del lato 2 self.etichetta2 = Label(self, text="Lato 2 ") |
Linea 191: | Linea 705: |
self.entrata2=Entry(self) # Casella d'inserimento del lato 2 |
self.entrata2 = Entry(self) |
Linea 195: | Linea 708: |
self.etichetta3=Label(self, text="Lato 3 ") # Etichetta del lato 3 | # Etichetta e casella d'inserimento del lato 3 self.etichetta3 = Label(self, text="Lato 3 ") |
Linea 197: | Linea 711: |
self.entrata3=Entry(self) # Casella d'inserimento del lato 3 |
self.entrata3 = Entry(self) |
Linea 201: | Linea 714: |
self.bottone=Button(self, text="Calcola", command=self.calcola) # Bottone "Calcola" | # Pulsante "Calcola" self.bottone = Button(self, text="Calcola", command=self.calcola) |
Linea 204: | Linea 718: |
self.risultato=Label(self, textvariable=self.ris) # Testo che motra il risultato. | # Mostra il risultato. self.risultato = Label(self, textvariable=self.ris) |
Linea 207: | Linea 722: |
# Raccogliamo l'input e calcoliamo l'area def calcola(self): try : a=float(self.entrata1.get()) b=float(self.entrata2.get()) c=float(self.entrata3.get()) t=Triangolo(a,b,c) self.ris.set("Area = "+str(t.area())) except ValueError: self.ris.set("Devi inserire valori numerici.") except "TriangoloImpossibile": self.ris.set("I lati immessi non possono formare un triangolo") |
def calcola(self): """Acquisisce l'input, lo valida e calcola l'area.""" try : # Legge i dati inseriti in ogni casella. a = float(self.entrata1.get()) b = float(self.entrata2.get()) c = float(self.entrata3.get()) t = Triangolo(a, b, c) except ValueError: # Cattura l'errore di tipo di dati. self.ris.set("Devi inserire valori numerici.") except TriangoloImpossibile as err: self.ris.set(err.message) else: # Nessun errore, espone il risultato. self.ris.set(f"Area = {t.area()}") |
Linea 222: | Linea 738: |
d=Dialogo() d.mainloop() |
d=Dialogo() d.mainloop() |
Linea 228: | Linea 745: |
Questa è una versione del programma `AreaTriangolo2.py`, presente all'interno di [[Programmazione/Python/ListatiPython3#areatraingolo2| questa pagina]], che utilizza le librerie '''wxpython'''. == Esempio di applicazione == |
##Qua manca una succinta descrizione. Per usare il programma [[AmministrazioneSistema/InstallareProgrammi|installare]] il pacchetto [[apt://python3-wxgtk4.0|python3-wxgtk4.0]]. ##Il pacchetto fornisce il modulo '''wx''', il quale provvede ai collegamenti '''Python3''' alle librerie '''wxgtk''' versione 4 e seguenti. === Esempio di applicazione === |
Linea 234: | Linea 755: |
import wx #importiamo l'interfaccia grafica from string import digits # importiamo una variabile per il controllo dei dati in input from math import sqrt # importiamo la funzione sqrt per il calcolo della radicequadrata dal modulo math |
import wx # Importa il modulo per l'interfaccia grafica from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math class TriangoloImpossibile(Exception): """Classe per sollevare un'eccezione se vengono immesse misure incompatibili.""" def __init__(self, message="Un triangolo con questi lati non esiste."): self.message = message class Triangolo: """Classe per costruire e validare gli oggetti triangolo da calcolare. Oltre al costruttore, la classe ha due metodi: un metodo che calcola il perimetro e uno che calcola l'area. Attributi della classe sono le misure dei tre lati a, b, c """ def __init__(self, a, b, c): """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__ Controlla se i tre valori immessi sono accettabili, cioè se sono validi come misure dei lati di un triangolo. In caso contrario solleva una eccezione TriangoloImpossibile. """ if a + b > c and a + c > b and b + c > a: self.a = a self.b = b self.c = c else: raise TriangoloImpossibile def perimetro(self): """Calcola il perimetro. Ritorna un numero in virgola mobile.""" return self.a + self.b + self.c def area(self): """Calcola l'area con la formula di Erone. Ritorna un numero in virgola mobile.""" p = self.perimetro() / 2 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c)) |
Linea 240: | Linea 799: |
def __init__(self, parent, title): super(Example,self).__init__(parent, title = title, size = (400,300)) self.InitUI() def calcola(self, evt): a=str(self.latoa.GetValue()) b=str(self.latob.GetValue()) c=str(self.latoc.GetValue()) vero = self.Contronum(a) if vero == "F": avviso = "Il lato a ="+ a+" <-- non e' di tipo numerico; Riprova " msg = wx.MessageBox( avviso, 'Errore',wx.OK | wx.ICON_ERROR) return vero = self.Contronum(b) if vero == "F": avviso = "Il lato b ="+ b+" <-- non e' di tipo numerico; Riprova " msg = wx.MessageBox( avviso, 'Errore',wx.OK | wx.ICON_ERROR) return vero = self.Contronum(c) if vero == "F": avviso = "Il lato c ="+ c+" <-- non e' di tipo numerico; Riprova " msg = wx.MessageBox( avviso, 'Errore',wx.OK | wx.ICON_ERROR) return # li trasforma in virgola mobile e poi verifica che corrispondano ad un triangolo a = float(a) b = float(b) c = float(c) p = (a+b+c)/2.0 if p <=a or p <= b or p <= c: avviso ='I dati immessi non sono quelli di un triangolo; Riprova' msg = wx.MessageBox( avviso, 'Errore',wx.OK | wx.ICON_ERROR) return else: # calcolo area triangolo area =sqrt(p*(p-a)*(p-b)*(p-c)) avviso =" L'area del triangolo misura Mq "+str(area) msg = wx.MessageBox( avviso, 'Risultato',wx.OK ) return def InitUI(self): font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT) self.panel = wx.Panel(self) self.panel.SetBackgroundColour("red") self.lato1 = wx.StaticText(self.panel, label = 'Lato 1') self.lato1.SetFont(font) self.lato1.SetForegroundColour((0,0,0)) self.lato1.SetPosition((10,10)) self.latoa = wx.TextCtrl(self.panel) self.latoa.SetFont(font) self.latoa.SetPosition((60,6)) self.lato2 = wx.StaticText(self.panel, label = 'Lato 2') self.lato2.SetFont(font) self.lato2.SetForegroundColour((0,0,0)) self.lato2.SetPosition((10,50)) self.latob = wx.TextCtrl(self.panel) self.latob.SetFont(font) self.latob.SetPosition((60,45)) self.lato3 = wx.StaticText(self.panel, label = 'Lato 3') self.lato3.SetFont(font) self.lato3.SetForegroundColour((0,0,0)) self.lato3.SetPosition((10,90)) self.latoc = wx.TextCtrl(self.panel) self.latoc.SetFont(font) self.latoc.SetPosition((60,85)) self.bottone = wx.Button(self.panel, label = 'Calcola') self.bottone.SetPosition((310, 235)) self.Bind(wx.EVT_BUTTON, self.calcola, self.bottone) def Contronum(self,valore): # serve per la verifica che i dati immessi siano di tipo numerico vero = "F" for i in range(len(valore)): if valore[i] in digits : vero = "T" continue else: vero = "F" break return vero |
"""Classe che gestisce l'interfaccia grafica ed esegue i calcoli.""" def __init__(self, parent, title): super(Example,self).__init__(parent, title=title, size=(400,300)) self.InitUI() def calcola(self, evt): """Acquisisce l'input, lo valida e calcola l'area.""" try: # legge i dati inseriti in ogni casella a = float(self.latoa.GetValue()) b = float(self.latob.GetValue()) c = float(self.latoc.GetValue()) triangolo = Triangolo(a, b, c) except ValueError: # cattura l'errore di tipo di dati avviso = "Bisogna inserire valori numerici." _ = wx.MessageBox( avviso, 'Errore', wx.OK | wx.ICON_ERROR) except TriangoloImpossibile as err: # cattura l'errore di dati non possibili _ = wx.MessageBox(err.message, 'Errore', wx.OK | wx.ICON_ERROR) else: # Nessun errore, espone il risultato avviso =f" L'area del triangolo misura {triangolo.area()}" _ = wx.MessageBox(avviso, 'Risultato', wx.OK ) def InitUI(self): """Metodo che definisce l'interfaccia grafica.""" font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT) self.panel = wx.Panel(self) #self.panel.SetBackgroundColour("red") self.lato1 = wx.StaticText(self.panel, label='Lato 1') self.lato1.SetFont(font) #self.lato1.SetForegroundColour((0, 0, 0)) self.lato1.SetPosition((10, 10)) self.latoa = wx.TextCtrl(self.panel) self.latoa.SetFont(font) self.latoa.SetPosition((60, 6)) self.lato2 = wx.StaticText(self.panel, label='Lato 2') self.lato2.SetFont(font) #self.lato2.SetForegroundColour((0, 0, 0)) self.lato2.SetPosition((10, 50)) self.latob = wx.TextCtrl(self.panel) self.latob.SetFont(font) self.latob.SetPosition((60, 45)) self.lato3 = wx.StaticText(self.panel, label='Lato 3') self.lato3.SetFont(font) #self.lato3.SetForegroundColour((0, 0, 0)) self.lato3.SetPosition((10, 90)) self.latoc = wx.TextCtrl(self.panel) self.latoc.SetFont(font) self.latoc.SetPosition((60, 85)) self.bottone = wx.Button(self.panel, label = 'Calcola') self.bottone.SetPosition((310, 235)) self.Bind(wx.EVT_BUTTON, self.calcola, self.bottone) |
Linea 337: | Linea 859: |
app = wx.App() ex = Example(None, title = "Calcolo area triangolo") ex.Show() app.MainLoop() |
app = wx.App() ex = Example(None, title = "Calcolo area triangolo") ex.Show() app.MainLoop() |
Linea 343: | Linea 865: |
main() | main() |
Linea 348: | Linea 871: |
* [[http://wiki.python.org/moin/GuiProgramming|Programmare interfacce grafiche con Python]] * [[http://www.wxpython.org|Sito ufficiale di wxpython]] * [[http://www.pygtk.org/|Sito ufficiale di PyGTK]] * [[http://www.tcl.tk/|Sito degli sviluppatori tcl/tk]] * [[http://www.python.it/|Sito di riferimento per i programmatori python italiani]] * [[http://www.python.org/|Il sito ufficiale del linguaggio python]] |
* [[http://wiki.python.org/moin/GuiProgramming|Lungo elenco di framework e toolkit per creare GUI con Python]] * [[https://python-gtk-3-tutorial.readthedocs.io/en/latest/|Tutorial per Python GTK+ 3]] * [[https://doc.qt.io/qtforpython/#documentation|Documentazione di Qt per Python]] * [[https://docs.python.org/3/library/tkinter.html|Documentazione di tkinter]] * [[https://docs.wxpython.org/|Documentazione di wxPython]] * [[http://www.python.it/|Sito di riferimento per i programmatori Python italiani]] * [[http://www.python.org/|Il sito ufficiale del linguaggio Python]] |
Guida verificata con Ubuntu: 20.04 22.04
Problemi in questa pagina? Segnalali in questa discussione
Introduzione
Questa pagina presenta alcuni esempi su come creare con Python programmi dotati di una semplice interfaccia grafica usando uno dei moduli GTK, PyQt, tkinter o wxPython che si appoggiano tutti a librerie Open Source e multipiattaforma.
In ciascuno di questi esempi viene realizzata una versione grafica di AreaTriangolo_con_eccezioni.py, script presente all'interno di questa pagina
Poiché tutti i moduli citati e le loro librerie usano la programmazione orientata agli oggetti, è possibile riutilizzare in maniera modulare lo stesso codice in più applicazioni riducendo tempo e risorse per lo sviluppo.
GTK
GTK+ è un toolkit per la creazione di interfacce grafiche che è stato progettato inizialmente come ausilio alla programmazione per GIMP ed è diventato una parte fondamentale dell'ambiente GNOME.
Il programma è preinstallato in Ubuntu. Nel caso fosse stato inavvertitamente rimosso o mancasse installare il pacchetto python3-gi.
Esempio di applicazione
1 #!/usr/bin/python3
2
3 import gi
4 gi.require_version('Gtk', '3.0')
5 from gi.repository import Gtk # Importa il modulo per l'interfaccia grafica
6 from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math
7
8 class TriangoloImpossibile(Exception):
9 """Classe per sollevare un'eccezione se vengono immesse misure incompatibili."""
10
11 def __init__(self, message="Un triangolo con questi lati non esiste."):
12 self.message = message
13
14
15 class Triangolo:
16 """Classe per costruire e validare gli oggetti triangolo da calcolare.
17
18 Oltre al costruttore, la classe ha due metodi:
19 un metodo che calcola il perimetro e uno che calcola l'area.
20 Attributi della classe sono le misure dei tre lati a, b, c
21 """
22
23 def __init__(self, a, b, c):
24 """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__
25
26 Controlla se i tre valori immessi sono accettabili,
27 cioè se sono validi come misure dei lati di un triangolo.
28 In caso contrario solleva una eccezione TriangoloImpossibile.
29 """
30 if a + b > c and a + c > b and b + c > a:
31 self.a = a
32 self.b = b
33 self.c = c
34 else:
35 raise TriangoloImpossibile
36
37 def perimetro(self):
38 """Calcola il perimetro. Ritorna un numero in virgola mobile."""
39 return self.a + self.b + self.c
40
41 def area(self):
42 """Calcola l'area con la formula di Erone. Ritorna un numero in virgola mobile."""
43 p = self.perimetro() / 2
44 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c))
45
46
47 class Finestra(Gtk.Window):
48 """Classe che definisce l'interfaccia grafica."""
49
50 def __init__(self):
51 Gtk.Window.__init__(self, title="Calcolo area triangolo")
52
53 self.riga1 = Gtk.HBox()
54 self.riga2 = Gtk.HBox()
55 self.riga3 = Gtk.HBox()
56 self.colonna = Gtk.VBox()
57
58 self.label1 = Gtk.Label(label="Lato 1 ")
59 self.label2 = Gtk.Label(label="Lato 2 ")
60 self.label3 = Gtk.Label(label="Lato 3 ")
61 self.entry1 = Gtk.Entry()
62 self.entry2 = Gtk.Entry()
63 self.entry3 = Gtk.Entry()
64 self.button = Gtk.Button(label="Calcola")
65 self.button.connect("clicked", self.calcola)
66 self.risultato = Gtk.Label(label=" -- ")
67
68 self.riga1.pack_start(self.label1, True, True, 0)
69 self.riga1.pack_start(self.entry1, True, True, 0)
70 self.riga2.pack_start(self.label2, True, True, 0)
71 self.riga2.pack_start(self.entry2, True, True, 0)
72 self.riga3.pack_start(self.label3, True, True, 0)
73 self.riga3.pack_start(self.entry3, True, True, 0)
74
75 self.colonna.pack_start(self.riga1, True, True, 7)
76 self.colonna.pack_start(self.riga2, True, True, 7)
77 self.colonna.pack_start(self.riga3, True, True, 7)
78 self.colonna.pack_start(self.risultato, True, True, 0)
79 self.colonna.pack_start(self.button, True, True, 3)
80 self.add(self.colonna)
81
82 def calcola(self, widget):
83 """Acquisisce l'input, lo valida e calcola l'area."""
84 try: # Legge i dati inseriti in ogni casella.
85 a = float(self.entry1.get_text())
86 b = float(self.entry2.get_text())
87 c = float(self.entry3.get_text())
88 triangolo = Triangolo(a, b, c)
89 except ValueError: # Cattura l'errore di tipo di dati.
90 self.risultato.set_text("Devi inserire valori numerici.")
91 except TriangoloImpossibile as err: # Cattura l'errore di dati non possibili.
92 self.risultato.set_text(err.message)
93 else: # Nessun errore, espone il risultato.
94 self.risultato.set_text(f"Area = {triangolo.area()}")
95
96 win = Finestra()
97 win.connect("destroy", Gtk.main_quit)
98 win.set_resizable(False)
99 #win.set_default_size(100,120)
100 win.show_all()
101 Gtk.main()
PyQt
Qt è un insieme di librerie usate per fornire di interfaccia grafica applicazioni e ambienti desktop (è tra l'altro parte integrante dell'ambiente grafico KDE Plasma).
Per la serie 5 delle librerie Qt il supporto cesserà a maggio 2023. È consigliato usare per i nuovi progetti la versione 6.
Installazione
Pacchetto deb
Per usare le librerie nella versione Qt5 installare il pacchetto python3-pyqt5.
Per usare le librerie nella versione Qt6 da Ubuntu 22.10 e successivi installare il pacchetto python3-pyqt6.
Fino a Ubuntu 22.04 la versione 6 della suite di pacchetti Python3-PyQt6 non è disponibile nei repository ufficiali.
In alternativa possono essere installati tramite il PPA Qt 6.2.x - backports, che fornisce sia versioni più recenti delle librerie Qt6 rispetto a quelle del repository ufficiale, sia la suite di pacchetti Python3-PyQt6 fino a Ubuntu 22.04.
Digitare nel terminale il comando:
sudo add-apt-repository ppa:savoury1/qt-6-2
Aggiornare il database dei pacchetti:
sudo apt update
Installare il pacchetto python3-pyqt6.
Tramite pip
installare il pacchetto pip3.
Digitare nel terminale, in funzione della versione scelta, uno dei seguenti comandi:
pip3 install pyQt5
o
pip3 install pyQt6
Esempio di applicazione
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math
5 import sys
6 # NB questo script può funzionare sia con le PyQt6 che con le PyQt5.
7 # Nel secondo caso bisogna sostituire nelle tre righe seguenti `PyQt6' con: `PyQt5'
8 from PyQt6.QtCore import Qt
9 from PyQt6 import QtGui
10 from PyQt6.QtWidgets import (QApplication, QDialog, QGridLayout,
11 QHBoxLayout, QLabel, QLineEdit,
12 QPushButton, QSizePolicy, QVBoxLayout
13 )
14
15 class Ui_Dialog(object):
16 """Classe che crea il widget contenitore di tutta l'nterfaccia grafica"""
17 def setupUi(self, Dialog):
18 Dialog.resize(300, 200)
19 Dialog.setWindowTitle("Calcolo area triangolo")
20 self.verticalLayout = QVBoxLayout(Dialog)
21 self.gridLayout = QGridLayout()
22
23 self.label_lato1 = QLabel()
24 self.label_lato1.setText("Lato 1")
25 self.input_lato1 = QLineEdit()
26 self.gridLayout.addWidget(self.label_lato1, 0, 0, 1, 1)
27 self.gridLayout.addWidget(self.input_lato1, 0, 1, 1, 1)
28
29 self.label_lato2 = QLabel()
30 self.label_lato2.setText("Lato 2")
31 self.input_lato2 = QLineEdit()
32 self.gridLayout.addWidget(self.label_lato2, 1, 0, 1, 1)
33 self.gridLayout.addWidget(self.input_lato2, 1, 1, 1, 1)
34
35 self.label_lato3 = QLabel()
36 self.label_lato3.setText("Lato 3")
37 self.input_lato3 = QLineEdit()
38 self.gridLayout.addWidget(self.label_lato3, 2, 0, 1, 1)
39 self.gridLayout.addWidget(self.input_lato3, 2, 1, 1, 1)
40
41 self.verticalLayout.addLayout(self.gridLayout)
42
43 self.esito = QLabel()
44 sizePolicy = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Expanding)
45 sizePolicy.setHorizontalStretch(0)
46 sizePolicy.setVerticalStretch(0)
47 sizePolicy.setHeightForWidth(self.esito.sizePolicy().hasHeightForWidth())
48 self.esito.setSizePolicy(sizePolicy)
49 self.esito.setAlignment(Qt.AlignmentFlag.AlignCenter)
50 self.esito.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
51 self.esito.setCursor(QtGui.QCursor(Qt.CursorShape.IBeamCursor))
52 font = QtGui.QFont()
53 font.setPointSize(12)
54 font.setBold(True)
55 font.setWeight(75)
56 self.esito.setFont(font)
57 self.esito.setTextFormat(Qt.TextFormat.RichText)
58 self.esito.setWordWrap(False)
59 self.esito.setText(". . .")
60
61 self.esito_HLayout = QHBoxLayout()
62 self.esito_HLayout.addWidget(self.esito, Qt.AlignmentFlag.AlignCenter)
63 self.verticalLayout.addLayout(self.esito_HLayout)
64
65 self.button_horizontalLayout = QHBoxLayout()
66 self.button_ok = QPushButton("Calcola")
67 self.button_ok.setFixedSize(80,40)
68 self.button_horizontalLayout.addWidget(self.button_ok, Qt.AlignmentFlag.AlignCenter)
69 self.verticalLayout.addLayout(self.button_horizontalLayout)
70 self.button_ok.clicked.connect(self.OK)
71
72
73 def OK(self):
74 self.esito.setText(self.calcoli())
75
76 def calcoli(self):
77 """Acquisisce l'input, lo valida e calcola l'area."""
78
79 try: # Legge i dati inseriti in ogni casella.
80 a = float(self.input_lato1.text())
81 b = float(self.input_lato2.text())
82 c = float(self.input_lato3.text())
83 triangolo = Triangolo(a, b, c)
84 except ValueError: # Cattura l'errore di tipo di dati.
85 risultato = "Devi inserire valori numerici."
86 except TriangoloImpossibile as err: # Cattura l'errore di dati non possibili.
87 risultato = err.message
88 else: # Nessun errore, espone il risultato.
89 risultato = f"Area = {triangolo.area()}"
90 return risultato
91
92
93 class TriangoloImpossibile(Exception):
94 """Classe per sollevare un'eccezione se vengono immesse misure incompatibili."""
95
96 def __init__(self, message="Un triangolo con questi lati non esiste."):
97 self.message = message
98
99
100 class Triangolo:
101 """Classe per costruire e validare gli oggetti triangolo da calcolare.
102
103 Oltre al costruttore, la classe ha due metodi:
104 un metodo che calcola il perimetro e uno che calcola l'area.
105 Attributi della classe sono le misure dei tre lati a, b, c
106 """
107
108 def __init__(self, a, b, c):
109 """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__
110
111 Controlla se i tre valori immessi sono accettabili,
112 cioè se sono validi come misure dei lati di un triangolo.
113 In caso contrario solleva l'eccezione TriangoloImpossibile.
114 """
115 if a + b > c and a + c > b and b + c > a:
116 self.a = a
117 self.b = b
118 self.c = c
119 else:
120 raise TriangoloImpossibile
121
122 def perimetro(self):
123 """Calcola il perimetro. Ritorna un numero in virgola mobile."""
124 return self.a + self.b + self.c
125
126 def area(self):
127 """Calcola l'area con la formula di Erone. Ritorna un numero in virgola mobile."""
128 p = self.perimetro() / 2
129 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c))
130
131
132 if __name__ == "__main__":
133 import sys
134 app = QApplication(sys.argv)
135 Dialog = QDialog()
136 ui = Ui_Dialog()
137 ui.setupUi(Dialog)
138 Dialog.show()
139 sys.exit(app.exec())
Un esempio più avanzato della stessa applicazione
Questo script funziona solo con Qt6.
1 #!/usr/bin/python3
2 # -*- coding: utf-8 -*-
3
4 from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math
5 import sys
6 from PyQt6 import QtCore, QtGui
7 from PyQt6.QtWidgets import (QApplication, QDialog, QGridLayout, QHBoxLayout,
8 QLabel, QLineEdit, QPushButton, QVBoxLayout
9 )
10
11 INTESTAZIONE = {'input': "Inserire le misure",
12 'error': "Errore",
13 'end': ""
14 }
15
16 class Ui_Dialog(object):
17 """Classe che crea il widget contenitore di tutta l'nterfaccia grafica"""
18
19 def setupUi(self, Dialog):
20 Dialog.resize(400, 250)
21 Dialog.setWindowTitle("Calcolo dell'area di un triangolo")
22 #icon = QtGui.QIcon('/percorso/di/una/icona.svg')
23 #Dialog.setWindowIcon(icon)
24 self.verticalLayout = QVBoxLayout(Dialog)
25 self.gridLayout = QGridLayout()
26
27 self.intestazione = QLabel(Dialog)
28 font = QtGui.QFont()
29 font.setPointSize(12)
30 font.setBold(True)
31 font.setWeight(75)
32 self.intestazione.setFont(font)
33 self.intestazione.setTextFormat(QtCore.Qt.TextFormat.RichText)
34 self.intestazione.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
35 self.intestazione.setText(INTESTAZIONE['input'])
36 self.intestazione.default_ss = self.intestazione.styleSheet() # salva lo styleSheet originale
37 self.verticalLayout.addWidget(self.intestazione)
38
39 self.label_lato1 = QLabel()
40 self.label_lato1.setText("Lato 1")
41 self.input_lato1 = MyLineEdit("1")
42 self.gridLayout.addWidget(self.input_lato1, 0, 0, 1, 1)
43 self.gridLayout.addWidget(self.label_lato1, 0, 1, 1, 1)
44
45 self.label_lato2 = QLabel()
46 self.label_lato2.setText("Lato 2")
47 self.input_lato2 = MyLineEdit("2")
48 self.gridLayout.addWidget(self.input_lato2, 1, 0, 1, 1)
49 self.gridLayout.addWidget(self.label_lato2, 1, 1, 1, 1)
50
51 self.label_lato3 = QLabel()
52 self.label_lato3.setText("Lato 3")
53 self.input_lato3 = MyLineEdit("3")
54 self.gridLayout.addWidget(self.input_lato3, 2, 0, 1, 1)
55 self.gridLayout.addWidget(self.label_lato3, 2, 1, 1, 1)
56
57 self.verticalLayout.addLayout(self.gridLayout)
58
59 self.messaggio = QLabel(Dialog)
60 self.messaggio.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.TextSelectableByMouse)
61 self.messaggio.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.IBeamCursor))
62 font = QtGui.QFont()
63 font.setPointSize(12)
64 font.setBold(True)
65 font.setWeight(75)
66 self.messaggio.setFont(font)
67 self.messaggio.setTextFormat(QtCore.Qt.TextFormat.RichText)
68 self.messaggio.setWordWrap(False)
69 self.messaggio.setText("")
70 self.horizontalLayout_messaggio = QHBoxLayout()
71 self.horizontalLayout_messaggio.addWidget(self.messaggio, QtCore.Qt.AlignmentFlag.AlignLeft)
72
73 self.gridLayout.addLayout(self.horizontalLayout_messaggio, 3, 0, 1, 2)
74
75 self.button_ok = QPushButton("Calcola")
76 self.button_ok.setEnabled(False)
77 self.button_ok.setFixedSize(80,40)
78 self.button_cancel = QPushButton("Annulla")
79 self.button_cancel.setFixedSize(80,40)
80 self.button_cancel.setStyleSheet("QToolTip {background-color: #ffffbb; \
81 color: black; \
82 font: 9pt; \
83 border-radius: 3px}"
84 )
85 self.button_cancel.setToolTip("Per uscire")
86 self.horizontalLayout_buttons = QHBoxLayout()
87 self.horizontalLayout_buttons.addWidget(self.button_ok,
88 QtCore.Qt.AlignmentFlag.AlignRight
89 )
90 self.horizontalLayout_buttons.addWidget(self.button_cancel,
91 QtCore.Qt.AlignmentFlag.AlignRight
92 )
93 self.gridLayout.addLayout(self.horizontalLayout_buttons, 4, 1, 1, 1)
94 self.button_ok.clicked.connect(self.OK)
95 self.button_cancel.clicked.connect(Dialog.reject)
96
97 Dialog.setTabOrder(self.input_lato1, self.input_lato2)
98 Dialog.setTabOrder(self.input_lato2, self.input_lato3)
99 Dialog.setTabOrder(self.input_lato3, self.button_ok)
100 Dialog.setTabOrder(self.button_ok, self.button_cancel)
101
102
103 def check(self):
104 """Viene eseguito da validazione() di ogni campo se ha input valido.
105
106 Se tutti i campi sono validi, abilita il pulsante "Calcola".
107 """
108 for campo in [self.input_lato1, self.input_lato2, self.input_lato3]:
109 is_valid = getattr(campo, 'isValid')
110 if not is_valid:
111 break
112 if is_valid:
113 self.button_ok.setEnabled(True)
114
115
116 def OK(self):
117 self.messaggio.setText(self.calcoli())
118
119
120 def calcoli(self) -> str:
121 """Acquisisce l'input, lo valida e restituisce l'area.
122
123 Viene eseguito quando viene cliccato il pulsante "Calcola".
124 Legge i dati da ogni campo e cambia il formato da it_IT.UTF-8 a C
125 per potere convertire le stringhe in numero a virgola mobile
126 con float().
127 Il formato del risultato viene restituito in it_IT.UTF-8
128 """
129 #
130 a = float(self.input_lato1.text().replace('.', '').replace(',', '.'))
131 b = float(self.input_lato2.text().replace('.', '').replace(',', '.'))
132 c = float(self.input_lato3.text().replace('.', '').replace(',', '.'))
133 try:
134 triangolo = Triangolo(a, b, c)
135 except TriangoloImpossibile as err: # Errore di dati incompatibili.
136 risultato = err.message
137 self.set_error_format()
138 else:
139 risultato = f"Area = {triangolo.area():.5g}".replace('.', ',')
140 self.intestazione.setText(INTESTAZIONE['end'])
141 return risultato
142
143 def set_error_format(self):
144 """Formatta e compila Intestazione e Risultato in caso di errore."""
145 self.intestazione.setStyleSheet("color: red")
146 self.intestazione.setText(INTESTAZIONE['error'])
147 self.messaggio.setStyleSheet("color: red")
148
149
150 class TriangoloImpossibile(Exception):
151 """Classe per sollevare un'eccezione se vengono immesse misure incompatibili."""
152
153 def __init__(self, message="Un triangolo con questi lati non esiste."):
154 self.message = message
155
156
157 class Triangolo:
158 """Classe per costruire e validare l'oggetto triangolo da calcolare.
159
160 Oltre al costruttore, la classe ha due metodi:
161 un metodo che calcola il perimetro e uno che calcola l'area.
162 Attributi della classe sono le misure dei tre lati a, b, c
163 """
164
165 def __init__(self, a, b, c):
166 """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__
167
168 Controlla se i tre valori immessi sono accettabili,
169 cioè se sono validi come misure dei lati di un triangolo.
170 In caso contrario solleva una eccezione TriangoloImpossibile.
171 """
172 if a + b > c and a + c > b and b + c > a:
173 self.a, self.b, self.c = a, b, c
174 else:
175 raise TriangoloImpossibile
176
177 def perimetro(self) -> float:
178 """Calcola il perimetro."""
179 return self.a + self.b + self.c
180
181 def area(self) -> float:
182 """Calcola l'area con la formula di Erone."""
183 p = self.perimetro() / 2
184 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c))
185
186
187 class MyLineEdit(QLineEdit):
188 """Classe per istanziare i campi di input dei lati.
189
190 Il campo viene formattato durante la scrittura in base all'input digitato:
191 ha una maschera di input che accetta solo interi o decimali >= 0,00001
192 L'input è giudicato valido in base al formato numerico locale: n.nnn,nnnnn
193 Per informare di questo, un tooltip compare passando il cursore sul campo.
194 """
195
196 def __init__(self, *args):
197 super(MyLineEdit, self).__init__()
198 self.setStyleSheet("QToolTip {background-color: #ffffbb; \
199 color: black; \
200 font: 9pt; \
201 border-radius: 3px}"
202 )
203 self.tooltip = "Usare la virgola come<br>separatore decimale"
204 self.setToolTip(self.tooltip)
205 self.default_ss = self.styleSheet() # salva lo styleSheet originale
206 self.bg_colors = {'green': '#b6ffb5', 'yellow': '#ffff7d'}
207 for arg in args:
208 self.myLabel = getattr(ui, f"label_lato{arg}") # serve per la formattazione
209 self.setPlaceholderText(f"Misura del {arg}° lato...")
210 self.textChanged.connect(self.validazione)
211 self.isValid = False # in partenza è vuoto
212 ## validatore
213 self.validator = QtGui.QDoubleValidator(bottom=0.00001, decimals=5)
214 self.validator.setNotation(QtGui.QDoubleValidator.Notation.StandardNotation)
215 self.setValidator(self.validator)
216
217
218 def focusOutEvent(self, event):
219 """Modifica la formattazione ogni volta che il campo perde il focus."""
220 super(MyLineEdit, self).focusOutEvent(event)
221 state = self.validazione()
222 if state is self.validator.State.Acceptable: # 2
223 self.default_format()
224 else:
225 self.invalid_format()
226
227
228 def validazione(self):
229 """Verifica se l'input del campo è valido o meno.
230
231 Si basa sul validatore QDoubleValidator che è anche maschera di input
232 e cioè impedisce l'immissione di caratteri non validi. Ma siccome si
233 può cambiare campo con qualsiasi contenuto, anche non valid, comunque
234 ritorna se la riga è valid o meno, per potere evidenziare l'errore.
235 """
236 state = self.validator.validate(self.text(), 0)[0]
237 if state is self.validator.State.Acceptable: # 2
238 self.isValid = True
239 ui.check()
240 bg_color = self.bg_colors['green']
241 elif state is self.validator.State.Intermediate: # 1
242 self.isValid = False
243 bg_color = self.bg_colors['yellow']
244 self.setStyleSheet(self.default_ss + 'QLineEdit {color: black; \
245 background-color: %s \
246 }' %bg_color
247 )
248 return state
249
250
251 def default_format(self):
252 """Ripristina lo styleSheet originale per segnalare input valido.
253
254 Viene eseguito all'uscita dal campo.
255 """
256 self.setStyleSheet(self.default_ss)
257 self.myLabel.setStyleSheet(self.default_ss)
258
259
260 def invalid_format(self):
261 """Formatta il campo e l'etichetta per segnalare input non valido.
262
263 Viene eseguito all'uscita dal campo.
264 """
265 self.setStyleSheet(self.default_ss + "QLineEdit {border: 1px solid red}")
266 self.myLabel.setStyleSheet("color: red")
267 ui.button_ok.setEnabled(False)
268
269
270 def focusInEvent(self, event):
271 """Ripristina lo styleSheet originale quando si torna sul campo."""
272 super(MyLineEdit, self).focusInEvent(event)
273 self.isValid = False
274 ui.intestazione.setStyleSheet(self.default_ss)
275 ui.intestazione.setText(INTESTAZIONE['input'])
276 ui.messaggio.setStyleSheet(self.default_ss)
277 ui.messaggio.setText("")
278 self.default_format()
279
280 if __name__ == "__main__":
281 import sys
282 app = QApplication(sys.argv)
283 Dialog = QDialog()
284 ui = Ui_Dialog()
285 ui.setupUi(Dialog)
286 Dialog.show()
287 sys.exit(app.exec())
Tkinter
Tk è un piccolo toolkit per la creazione di interfacce grafiche che oltre a Python è stato portato anche verso altri linguaggi come Ruby, Lisp etc.
Per usare il programma installare il pacchetto python3-tk.
Esempio di applicazione
1 #!/usr/bin/python3
2
3 from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math
4
5 # Importa widgets e altri attributi dal modulo per l'interfaccia grafica
6 from tkinter import Button, Entry, Frame, Label, StringVar, E, W, N, S
7
8
9 class TriangoloImpossibile(Exception):
10 """Classe per sollevare un'eccezione se vengono immesse misure incompatibili."""
11
12 def __init__(self, message="Un triangolo con questi lati non esiste."):
13 self.message = message
14
15
16 class Triangolo:
17 """Classe per costruire e validare gli oggetti triangolo da calcolare.
18
19 Oltre al costruttore, la classe ha due metodi:
20 un metodo che calcola il perimetro e uno che calcola l'area.
21 Attributi della classe sono le misure dei tre lati a, b, c
22 """
23
24 def __init__(self, a, b, c):
25 """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__
26
27 Controlla se i tre valori immessi sono accettabili,
28 cioè se sono validi come misure dei lati di un triangolo.
29 In caso contrario solleva una eccezione TriangoloImpossibile.
30 """
31 if a + b > c and a + c > b and b + c > a:
32 self.a = a
33 self.b = b
34 self.c = c
35 else:
36 raise TriangoloImpossibile
37
38 def perimetro(self):
39 """Calcola il perimetro. Ritorna un numero in virgola mobile."""
40 return self.a + self.b + self.c
41
42 def area(self):
43 """Calcola l'area con la formula di Erone. Ritorna un numero in virgola mobile."""
44 p = self.perimetro() / 2
45 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c))
46
47
48 class Dialogo(Frame):
49 """Classe che gestisce l'interfaccia grafica ed esegue i calcoli."""
50
51 def __init__(self):
52 Frame.__init__(self)
53 self.master.title("Area triangolo.") # Diamo il titolo alla finestra.
54 self.master.minsize(250, 150) # Dimensioni minime della finestra
55 self.grid(sticky=E+W+N+S)
56
57 self.ris = StringVar() # Questa variabile stringa viene usata per
58 self.ris.set("---") # aggiornare la gui quando il risultato cambia.
59
60 # Rende ridimensionabile la finestra dell'applicazione
61 top = self.winfo_toplevel()
62 top.rowconfigure(0, weight=1)
63 top.columnconfigure(0, weight=1)
64
65 for i in range(5):
66 self.rowconfigure(i, weight=1)
67 self.columnconfigure(1, weight=1)
68
69 # Etichetta e casella di input del lato 1
70 self.etichetta1 = Label(self, text="Lato 1 ")
71 self.etichetta1.grid(row=0, column=0, padx=2)
72 self.entrata1 = Entry(self)
73 self.entrata1.grid(row=0, column=1, pady=2, padx=2, sticky=E+W+N+S)
74
75 # Etichetta e casella d'inserimento del lato 2
76 self.etichetta2 = Label(self, text="Lato 2 ")
77 self.etichetta2.grid(row=1, column=0, padx=2)
78 self.entrata2 = Entry(self)
79 self.entrata2.grid(row=1, column=1, pady=2, padx=2, sticky=E+W+N+S)
80
81 # Etichetta e casella d'inserimento del lato 3
82 self.etichetta3 = Label(self, text="Lato 3 ")
83 self.etichetta3.grid(row=2, column=0, padx=2)
84 self.entrata3 = Entry(self)
85 self.entrata3.grid(row=2, column=1, pady=2, padx=2, sticky=E+W+N+S)
86
87 # Pulsante "Calcola"
88 self.bottone = Button(self, text="Calcola", command=self.calcola)
89 self.bottone.grid(row=3, column=0, columnspan=2, pady=2, padx=2, sticky=E+W+N+S)
90
91 # Mostra il risultato.
92 self.risultato = Label(self, textvariable=self.ris)
93 self.risultato.grid(row=4, column=0, columnspan=2, pady=2, padx=2, sticky=E+W+N+S)
94
95 def calcola(self):
96 """Acquisisce l'input, lo valida e calcola l'area."""
97 try : # Legge i dati inseriti in ogni casella.
98 a = float(self.entrata1.get())
99 b = float(self.entrata2.get())
100 c = float(self.entrata3.get())
101 t = Triangolo(a, b, c)
102 except ValueError: # Cattura l'errore di tipo di dati.
103 self.ris.set("Devi inserire valori numerici.")
104 except TriangoloImpossibile as err:
105 self.ris.set(err.message)
106 else: # Nessun errore, espone il risultato.
107 self.ris.set(f"Area = {t.area()}")
108
109 # Avvio del programma a condizione che non sia caricato come modulo
110 if __name__=="__main__":
111 d=Dialogo()
112 d.mainloop()
wxPython
Per usare il programma installare il pacchetto python3-wxgtk4.0.
Esempio di applicazione
1 #!/usr/bin/python3
2
3 import wx # Importa il modulo per l'interfaccia grafica
4 from math import sqrt # Importa la funzione sqrt (radice quadrata) dal modulo math
5
6
7 class TriangoloImpossibile(Exception):
8 """Classe per sollevare un'eccezione se vengono immesse misure incompatibili."""
9
10 def __init__(self, message="Un triangolo con questi lati non esiste."):
11 self.message = message
12
13
14 class Triangolo:
15 """Classe per costruire e validare gli oggetti triangolo da calcolare.
16
17 Oltre al costruttore, la classe ha due metodi:
18 un metodo che calcola il perimetro e uno che calcola l'area.
19 Attributi della classe sono le misure dei tre lati a, b, c
20 """
21
22 def __init__(self, a, b, c):
23 """Metodo costruttore. In Python i costruttori hanno il nome speciale __init__
24
25 Controlla se i tre valori immessi sono accettabili,
26 cioè se sono validi come misure dei lati di un triangolo.
27 In caso contrario solleva una eccezione TriangoloImpossibile.
28 """
29 if a + b > c and a + c > b and b + c > a:
30 self.a = a
31 self.b = b
32 self.c = c
33 else:
34 raise TriangoloImpossibile
35
36 def perimetro(self):
37 """Calcola il perimetro. Ritorna un numero in virgola mobile."""
38 return self.a + self.b + self.c
39
40 def area(self):
41 """Calcola l'area con la formula di Erone. Ritorna un numero in virgola mobile."""
42 p = self.perimetro() / 2
43 return sqrt(p * (p-self.a) * (p-self.b) * (p-self.c))
44
45
46 class Example(wx.Frame):
47 """Classe che gestisce l'interfaccia grafica ed esegue i calcoli."""
48
49 def __init__(self, parent, title):
50 super(Example,self).__init__(parent, title=title, size=(400,300))
51 self.InitUI()
52
53 def calcola(self, evt):
54 """Acquisisce l'input, lo valida e calcola l'area."""
55 try: # legge i dati inseriti in ogni casella
56 a = float(self.latoa.GetValue())
57 b = float(self.latob.GetValue())
58 c = float(self.latoc.GetValue())
59 triangolo = Triangolo(a, b, c)
60 except ValueError: # cattura l'errore di tipo di dati
61 avviso = "Bisogna inserire valori numerici."
62 _ = wx.MessageBox( avviso, 'Errore', wx.OK | wx.ICON_ERROR)
63 except TriangoloImpossibile as err: # cattura l'errore di dati non possibili
64 _ = wx.MessageBox(err.message, 'Errore', wx.OK | wx.ICON_ERROR)
65 else: # Nessun errore, espone il risultato
66 avviso =f" L'area del triangolo misura {triangolo.area()}"
67 _ = wx.MessageBox(avviso, 'Risultato', wx.OK )
68
69 def InitUI(self):
70 """Metodo che definisce l'interfaccia grafica."""
71 font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)
72 self.panel = wx.Panel(self)
73 #self.panel.SetBackgroundColour("red")
74 self.lato1 = wx.StaticText(self.panel, label='Lato 1')
75 self.lato1.SetFont(font)
76 #self.lato1.SetForegroundColour((0, 0, 0))
77 self.lato1.SetPosition((10, 10))
78
79 self.latoa = wx.TextCtrl(self.panel)
80 self.latoa.SetFont(font)
81 self.latoa.SetPosition((60, 6))
82
83 self.lato2 = wx.StaticText(self.panel, label='Lato 2')
84 self.lato2.SetFont(font)
85 #self.lato2.SetForegroundColour((0, 0, 0))
86 self.lato2.SetPosition((10, 50))
87
88 self.latob = wx.TextCtrl(self.panel)
89 self.latob.SetFont(font)
90 self.latob.SetPosition((60, 45))
91
92 self.lato3 = wx.StaticText(self.panel, label='Lato 3')
93 self.lato3.SetFont(font)
94 #self.lato3.SetForegroundColour((0, 0, 0))
95 self.lato3.SetPosition((10, 90))
96
97 self.latoc = wx.TextCtrl(self.panel)
98 self.latoc.SetFont(font)
99 self.latoc.SetPosition((60, 85))
100
101 self.bottone = wx.Button(self.panel, label = 'Calcola')
102 self.bottone.SetPosition((310, 235))
103 self.Bind(wx.EVT_BUTTON, self.calcola, self.bottone)
104
105
106 def main():
107 app = wx.App()
108 ex = Example(None, title = "Calcolo area triangolo")
109 ex.Show()
110 app.MainLoop()
111
112 if __name__ == '__main__':
113 main()