Sostengo un approccio orientato agli oggetti. Questo è il modello con cui inizio:
# Use Tkinter for python 2, tkinter for python 3
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
<create the rest of your GUI here>
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Le cose importanti da notare sono:
Non utilizzo un'importazione con caratteri jolly. Importo il pacchetto come "tk", che richiede il prefisso di tutti i comandi tk.
. Ciò previene l'inquinamento dello spazio dei nomi globale, inoltre rende il codice completamente ovvio quando si utilizzano classi Tkinter, classi tk o alcune delle proprie.
L'applicazione principale è una classe . Questo ti dà uno spazio dei nomi privato per tutti i tuoi callback e funzioni private, e in generale semplifica l'organizzazione del tuo codice. In uno stile procedurale devi scrivere il codice dall'alto verso il basso, definire le funzioni prima di usarle, ecc. Con questo metodo non lo fai poiché non crei effettivamente la finestra principale fino all'ultimo passaggio. Preferisco ereditare tk.Frame
solo perché in genere inizio creando un frame, ma non è assolutamente necessario.
Se la tua app ha finestre di livello superiore aggiuntive, ti consiglio di rendere ciascuna di queste una classe separata, ereditando da tk.Toplevel
. Questo ti dà tutti gli stessi vantaggi sopra menzionati: le finestre sono atomiche, hanno il loro spazio dei nomi e il codice è ben organizzato. Inoltre, semplifica l'inserimento di ciascuno nel proprio modulo una volta che il codice inizia a diventare grande.
Infine, potresti prendere in considerazione l'utilizzo delle classi per ogni parte principale della tua interfaccia. Ad esempio, se stai creando un'app con una barra degli strumenti, un riquadro di navigazione, una barra di stato e un'area principale, puoi creare ognuna di quelle classi. Questo rende il tuo codice principale abbastanza piccolo e facile da capire:
class Navbar(tk.Frame): ...
class Toolbar(tk.Frame): ...
class Statusbar(tk.Frame): ...
class Main(tk.Frame): ...
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.statusbar = Statusbar(self, ...)
self.toolbar = Toolbar(self, ...)
self.navbar = Navbar(self, ...)
self.main = Main(self, ...)
self.statusbar.pack(side="bottom", fill="x")
self.toolbar.pack(side="top", fill="x")
self.navbar.pack(side="left", fill="y")
self.main.pack(side="right", fill="both", expand=True)
Dato che tutte queste istanze condividono un genitore comune, il genitore diventa effettivamente la parte "controller" di un'architettura modello-view-controller. Quindi, ad esempio, la finestra principale potrebbe posizionare qualcosa sulla barra di stato chiamando self.parent.statusbar.set("Hello, world")
. Ciò consente di definire una semplice interfaccia tra i componenti, contribuendo a mantenere l'accoppiamento con un minimo.