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, num):
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 self.myLabel = getattr(ui, f"label_lato{num}") # serve per la formattazione
208 self.setPlaceholderText(f"Misura del {num}° lato...")
209 self.textChanged.connect(self.validazione)
210 self.isValid = False # in partenza è vuoto
211 ## validatore
212 self.validator = QtGui.QDoubleValidator(bottom=0.00001, decimals=5)
213 self.validator.setNotation(QtGui.QDoubleValidator.Notation.StandardNotation)
214 self.setValidator(self.validator)
215
216
217 def focusOutEvent(self, event):
218 """Modifica la formattazione ogni volta che il campo perde il focus."""
219 super(MyLineEdit, self).focusOutEvent(event)
220 state = self.validazione()
221 if state is self.validator.State.Acceptable: # 2
222 self.default_format()
223 else:
224 self.invalid_format()
225
226
227 def validazione(self):
228 """Verifica se l'input del campo è valido o meno.
229
230 Si basa sul validatore QDoubleValidator che è anche maschera di input
231 e cioè impedisce l'immissione di caratteri non validi. Ma siccome si
232 può cambiare campo con qualsiasi contenuto, anche non valid, comunque
233 ritorna se la riga è valid o meno, per potere evidenziare l'errore.
234 """
235 state = self.validator.validate(self.text(), 0)[0]
236 if state is self.validator.State.Acceptable: # 2
237 self.isValid = True
238 ui.check()
239 bg_color = self.bg_colors['green']
240 elif state is self.validator.State.Intermediate: # 1
241 self.isValid = False
242 bg_color = self.bg_colors['yellow']
243 self.setStyleSheet(self.default_ss + 'QLineEdit {color: black; \
244 background-color: %s \
245 }' %bg_color
246 )
247 return state
248
249
250 def default_format(self):
251 """Ripristina lo styleSheet originale per segnalare input valido.
252
253 Viene eseguito all'uscita dal campo.
254 """
255 self.setStyleSheet(self.default_ss)
256 self.myLabel.setStyleSheet(self.default_ss)
257
258
259 def invalid_format(self):
260 """Formatta il campo e l'etichetta per segnalare input non valido.
261
262 Viene eseguito all'uscita dal campo.
263 """
264 self.setStyleSheet(self.default_ss + "QLineEdit {border: 1px solid red}")
265 self.myLabel.setStyleSheet("color: red")
266 ui.button_ok.setEnabled(False)
267
268
269 def focusInEvent(self, event):
270 """Ripristina lo styleSheet originale quando si torna sul campo."""
271 super(MyLineEdit, self).focusInEvent(event)
272 self.isValid = False
273 ui.intestazione.setStyleSheet(self.default_ss)
274 ui.intestazione.setText(INTESTAZIONE['input'])
275 ui.messaggio.setStyleSheet(self.default_ss)
276 ui.messaggio.setText("")
277 self.default_format()
278
279 if __name__ == "__main__":
280 import sys
281 app = QApplication(sys.argv)
282 Dialog = QDialog()
283 ui = Ui_Dialog()
284 ui.setupUi(Dialog)
285 Dialog.show()
286 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()