## page was renamed from mtramonti2007/provaGUIPython3
## page was renamed from Programmazione/Python/GUI
## page was renamed from LinguaggioPython/GUI
#format wiki
#language it
<
>
<>
<>
= 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 [[Programmazione/Python/ListatiPython3#Listato_3| 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.
## * 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]].<
>
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 ===
{{{#!python
#!/usr/bin/python3
import gi
gi.require_version('Gtk', '3.0')
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
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))
class Finestra(Gtk.Window):
"""Classe che definisce l'interfaccia grafica."""
def __init__(self):
Gtk.Window.__init__(self, title="Calcolo area triangolo")
self.riga1 = Gtk.HBox()
self.riga2 = Gtk.HBox()
self.riga3 = Gtk.HBox()
self.colonna = Gtk.VBox()
self.label1 = Gtk.Label(label="Lato 1 ")
self.label2 = Gtk.Label(label="Lato 2 ")
self.label3 = Gtk.Label(label="Lato 3 ")
self.entry1 = Gtk.Entry()
self.entry2 = Gtk.Entry()
self.entry3 = Gtk.Entry()
self.button = Gtk.Button(label="Calcola")
self.button.connect("clicked", self.calcola)
self.risultato = Gtk.Label(label=" -- ")
self.riga1.pack_start(self.label1, True, True, 0)
self.riga1.pack_start(self.entry1, True, True, 0)
self.riga2.pack_start(self.label2, True, True, 0)
self.riga2.pack_start(self.entry2, True, True, 0)
self.riga3.pack_start(self.label3, True, True, 0)
self.riga3.pack_start(self.entry3, True, True, 0)
self.colonna.pack_start(self.riga1, True, True, 7)
self.colonna.pack_start(self.riga2, True, True, 7)
self.colonna.pack_start(self.riga3, True, True, 7)
self.colonna.pack_start(self.risultato, True, True, 0)
self.colonna.pack_start(self.button, True, True, 3)
self.add(self.colonna)
def calcola(self, widget):
"""Acquisisce l'input, lo valida e calcola l'area."""
try: # Legge i dati inseriti in ogni casella.
a = float(self.entry1.get_text())
b = float(self.entry2.get_text())
c = float(self.entry3.get_text())
triangolo = Triangolo(a, b, c)
except ValueError: # Cattura l'errore di tipo di dati.
self.risultato.set_text("Devi inserire valori numerici.")
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()}")
win = Finestra()
win.connect("destroy", Gtk.main_quit)
win.set_resizable(False)
#win.set_default_size(100,120)
win.show_all()
Gtk.main()
}}}
= 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.}}}
{{{#!python
#!/usr/bin/python3
# -*- 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
class Triangolo:
"""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, num):
super(MyLineEdit, self).__init__()
self.setStyleSheet("QToolTip {background-color: #ffffbb; \
color: black; \
font: 9pt; \
border-radius: 3px}"
)
self.tooltip = "Usare la virgola come
separatore decimale"
self.setToolTip(self.tooltip)
self.default_ss = self.styleSheet() # salva lo styleSheet originale
self.bg_colors = {'green': '#b6ffb5', 'yellow': '#ffff7d'}
self.myLabel = getattr(ui, f"label_lato{num}") # serve per la formattazione
self.setPlaceholderText(f"Misura del {num}° 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))
class Dialogo(Frame):
"""Classe che gestisce l'interfaccia grafica ed esegue i calcoli."""
def __init__(self):
Frame.__init__(self)
self.master.title("Area triangolo.") # Diamo il titolo alla finestra.
self.master.minsize(250, 150) # Dimensioni minime della finestra
self.grid(sticky=E+W+N+S)
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()
top.rowconfigure(0, weight=1)
top.columnconfigure(0, weight=1)
for i in range(5):
self.rowconfigure(i, weight=1)
self.columnconfigure(1, weight=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)
self.entrata1.grid(row=0, column=1, pady=2, padx=2, sticky=E+W+N+S)
# Etichetta e casella d'inserimento del lato 2
self.etichetta2 = Label(self, text="Lato 2 ")
self.etichetta2.grid(row=1, column=0, padx=2)
self.entrata2 = Entry(self)
self.entrata2.grid(row=1, column=1, pady=2, padx=2, sticky=E+W+N+S)
# Etichetta e casella d'inserimento del lato 3
self.etichetta3 = Label(self, text="Lato 3 ")
self.etichetta3.grid(row=2, column=0, padx=2)
self.entrata3 = Entry(self)
self.entrata3.grid(row=2, column=1, pady=2, padx=2, sticky=E+W+N+S)
# Pulsante "Calcola"
self.bottone = Button(self, text="Calcola", command=self.calcola)
self.bottone.grid(row=3, column=0, columnspan=2, pady=2, padx=2, sticky=E+W+N+S)
# Mostra il risultato.
self.risultato = Label(self, textvariable=self.ris)
self.risultato.grid(row=4, column=0, columnspan=2, pady=2, padx=2, sticky=E+W+N+S)
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()}")
# Avvio del programma a condizione che non sia caricato come modulo
if __name__=="__main__":
d=Dialogo()
d.mainloop()
}}}
= wxPython =
##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 ===
{{{#!python
#!/usr/bin/python3
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))
class Example(wx.Frame):
"""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)
def main():
app = wx.App()
ex = Example(None, title = "Calcolo area triangolo")
ex.Show()
app.MainLoop()
if __name__ == '__main__':
main()
}}}
= Ulteriori risorse =
* [[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]]
----
CategoryProgrammazione