Tkinter Grid Problem - Frame non allineati
Ho appena iniziato a lavorare con tkinter e sto ancora cercando di abituarmi a come funziona. Stavo cercando di preparare una sorta di menu a griglia con 4 sezioni.
C'è un frame in alto con il titolo dell'app, un frame a sinistra con alcuni pulsanti per configurare l'app e poi, 4 frame di uguali dimensioni nel resto.
Il mio problema principale qui è la colonna vuota tra il riquadro di sinistra e gli altri quattro, come posso regolarla in modo che i 4 quadrati riempiano quello spazio?
Vedi sotto il codice:
import datetime
import tkinter as tk
from time import strftime
window = tk.Tk()
window.geometry("1400x800")
window.configure(bg="white")
window.rowconfigure(20,weight=1)
window.columnconfigure(35,weight=1)
window.title("Hello World App")
entry_var_server = tk.StringVar(window,"")
entry_var_db = tk.StringVar(window,"")
entry_var_driver = tk.StringVar(window,"")
def window_widgets():
db_ini_frame_top = tk.Frame(master=window,bg="#57b956",height=120,width=1400,highlightbackground="black",highlightthickness=2)
db_ini_frame_top.grid(rowspan=3,columnspan=34,sticky="w")
db_ini_label_top = tk.Label(master=window,text="Hello World",bg="#57b956")
db_ini_label_top.configure(font=("Calibri",26))
db_ini_label_top.grid(row=1,column=18,sticky="n")
def cur_date(dic = {'01':'st','21':'st','31':'st',
'02':'nd','22':'nd',
'03':'rd','23':'rd'}):
x = strftime('%A, %B %d')
return x + dic.get(x[-2:],'th')+strftime(" %G - %H:%M")
date = cur_date()
db_ini_date = tk.Label(master=window,text=date,bg="#57b956")
db_ini_date.configure(font=("Calibri",12))
db_ini_date.grid(row=0,column=0,sticky="w")
db_ini_frame_left = tk.Frame(master=window,bg="light grey",height=800,width=120,colormap="new",highlightbackground="black",highlightthickness=2)
db_ini_frame_left.grid(row=3,rowspan=16,columnspan=2,sticky="w")
db_ini_frame_center_nw = tk.Frame(master=window,height=350,width=640,bg="blue")
db_ini_frame_center_nw.grid(row=3,column=3,columnspan=16,rowspan=12,sticky="nw")
db_ini_frame_center_sw = tk.Frame(master=window,height=450,width=640,bg="light blue")
db_ini_frame_center_sw.grid(row=12,column=3,columnspan=16,rowspan=12,sticky="sw")
db_ini_frame_center_ne = tk.Frame(master=window,height=350,width=640,bg="light blue")
db_ini_frame_center_ne.grid(row=3,column=19,columnspan=16,rowspan=12,sticky="ne")
db_ini_frame_center_se = tk.Frame(master=window,height=450,width=640,bg="blue")
db_ini_frame_center_se.grid(row=12,column=19,columnspan=16,rowspan=12,sticky="se")
window_widgets()
window.tk.mainloop()
Risposte
Sebbene possiamo correggere il tuo codice con solo un paio di piccole modifiche, impiegare alcuni minuti per creare un layout più intelligente renderà molto più semplice modificare il tuo codice man mano che l'applicazione cresce.
Ho intenzione di offrire alcuni consigli su come riorganizzare il tuo codice. Alla fine della risposta c'è un ultimo esempio di lavoro. Il 90% è il tuo codice originale, ma con alcune modifiche qua e là per rendere più semplice la creazione dell'interfaccia utente.
Non usare gridper tutto
Innanzitutto, ti consiglio di non utilizzare gridper tutto. È utile per creare griglie, ma a volte ci sono modi migliori per disporre un'intera finestra. Dividi la tua interfaccia utente in raggruppamenti logici, quindi disponili utilizzando quei raggruppamenti.
Organizzando la tua interfaccia utente in sezioni, è molto più facile modificare solo una singola sezione. Quando si utilizza gridper tutto, apportare una piccola modifica potrebbe richiedere la modifica di una dozzina di righe di codice in cui è necessario regolare i numeri di riga e di colonna e gli intervalli di riga e colonna per tutto solo per ospitare un singolo nuovo widget.
Raggruppa il codice del layout insieme
Ti consiglio anche di raggruppare le tue chiamate a gride packinsieme piuttosto che cospargerle in tutto il codice. Trovo che sia molto più facile visualizzare il layout e più facile apportare modifiche poiché tutte le modifiche correlate sono vicine l'una all'altra piuttosto che distribuite.
Dividi l'interfaccia utente in sezioni logiche
Hai chiaramente tre aree distinte: un titolo in alto, alcuni pulsanti a sinistra e poi tutto il resto. Quindi, inizia creando proprio questo. packè senza dubbio la scelta migliore quando hai cose disposte lungo i lati di uno spazio.
Quindi, inizia creando cornici per queste tre aree. È quindi possibile utilizzarli packper allinearli lungo i bordi secondo la descrizione.
db_ini_frame_top = tk.Frame(master=window, ...)
db_ini_frame_left = tk.Frame(master=window, ...)
db_ini_main = tk.Frame(master=window, ...)
db_ini_frame_top.pack(side="top", fill="x")
db_ini_frame_left.pack(side="left", fill="y")
db_ini_main.pack(side="top", fill="both", expand=True)
Posiziona altri widget in questi contenitori
Anche se hai creato una cornice in alto, stavi mettendo l'etichetta e la data nella finestra principale. Dovresti metterli all'interno della cornice. Quando arrivi ad aggiungere pulsanti, dovrebbero andare nel riquadro di sinistra. E infine, per le altre quattro finestre, devono andare nel terzo fotogramma.
db_ini_label_top = tk.Label(master=db_ini_frame_top, ...)
db_ini_date = tk.Label(master=db_ini_frame_top, ...)
db_ini_frame_center_nw = tk.Frame(master=db_ini_main, ...)
db_ini_frame_center_sw = tk.Frame(master=db_ini_main, ...)
db_ini_frame_center_ne = tk.Frame(master=db_ini_main, ...)
db_ini_frame_center_se = tk.Frame(master=db_ini_main, ...)
Utilizzare gridper i quattro fotogrammi che sono effettivamente in una griglia
Quando si utilizza grid, una regola pratica è che si dovrebbe dare ad almeno una riga e una colonna un peso in modo che gridsappia cosa fare con lo spazio extra man mano che la finestra si allarga o si restringe. Nel tuo caso vuoi che tutte e quattro le celle siano uguali, quindi dovresti dare a tutte lo stesso peso.
Poiché ora stai usando la griglia solo per queste quattro finestre invece di provare a forzare tutto in una singola griglia, puoi usare numeri di riga e colonna che hanno senso (ad esempio: righe 0 e 1, colonne 0 e 1, invece di righe artificialmente grandi e colonne e campate).
db_ini_frame_center_nw = tk.Frame(master=db_ini_main,height=350,width=640,bg="blue")
db_ini_frame_center_sw = tk.Frame(master=db_ini_main,height=450,width=640,bg="light blue")
db_ini_frame_center_ne = tk.Frame(master=db_ini_main,height=350,width=640,bg="light blue")
db_ini_frame_center_se = tk.Frame(master=db_ini_main,height=450,width=640,bg="blue")
db_ini_main.grid_rowconfigure((0,1), weight=1)
db_ini_main.grid_columnconfigure((0,1), weight=1)
db_ini_frame_center_nw.grid(row=0,column=0, sticky="nsew")
db_ini_frame_center_sw.grid(row=0,column=1, sticky="nsew")
db_ini_frame_center_ne.grid(row=1,column=0, sticky="nsew")
db_ini_frame_center_se.grid(row=1,column=1, sticky="nsew")
Questo è l'aspetto del tuo codice completo. Non ho modificato la posizione del testo nell'area del titolo, ma è facile modificarla senza influire sulle altre aree della GUI.
Inoltre, nota che puoi ridimensionare manualmente la finestra e tutto cresce o si restringe in modo appropriato piuttosto che lasciare punti vuoti.
import datetime
import tkinter as tk
from time import strftime
window = tk.Tk()
window.geometry("1400x800")
window.configure(bg="white")
window.rowconfigure(20,weight=1)
window.columnconfigure(35,weight=1)
window.title("Hello World App")
entry_var_server = tk.StringVar(window,"")
entry_var_db = tk.StringVar(window,"")
entry_var_driver = tk.StringVar(window,"")
def window_widgets():
db_ini_frame_top = tk.Frame(master=window,bg="#57b956",height=120,width=1400,highlightbackground="black",highlightthickness=2)
db_ini_frame_left = tk.Frame(master=window,bg="light grey",height=800,width=120,colormap="new",highlightbackground="black",highlightthickness=2)
db_ini_main = tk.Frame(master=window,bg="light grey",height=800,width=120,colormap="new",highlightbackground="black",highlightthickness=2)
db_ini_frame_top.pack(side="top", fill="x")
db_ini_frame_left.pack(side="left", fill="y")
db_ini_main.pack(side="top", fill="both", expand=True)
db_ini_label_top = tk.Label(master=db_ini_frame_top,text="Hello World",bg="#57b956")
db_ini_label_top.configure(font=("Calibri",26))
db_ini_label_top.grid(row=1,column=18,sticky="n")
def cur_date(dic = {'01':'st','21':'st','31':'st',
'02':'nd','22':'nd',
'03':'rd','23':'rd'}):
x = strftime('%A, %B %d')
return x + dic.get(x[-2:],'th')+strftime(" %G - %H:%M")
date = cur_date()
db_ini_date = tk.Label(master=db_ini_frame_top,text=date,bg="#57b956")
db_ini_date.configure(font=("Calibri",12))
db_ini_date.grid(row=0,column=0,sticky="w")
db_ini_frame_center_nw = tk.Frame(master=db_ini_main,height=350,width=640,bg="blue")
db_ini_frame_center_sw = tk.Frame(master=db_ini_main,height=450,width=640,bg="light blue")
db_ini_frame_center_ne = tk.Frame(master=db_ini_main,height=350,width=640,bg="light blue")
db_ini_frame_center_se = tk.Frame(master=db_ini_main,height=450,width=640,bg="blue")
db_ini_main.grid_rowconfigure((0,1), weight=1)
db_ini_main.grid_columnconfigure((0,1), weight=1)
db_ini_frame_center_nw.grid(row=0,column=0, sticky="nsew")
db_ini_frame_center_sw.grid(row=0,column=1, sticky="nsew")
db_ini_frame_center_ne.grid(row=1,column=0, sticky="nsew")
db_ini_frame_center_se.grid(row=1,column=1, sticky="nsew")
window_widgets()
window.tk.mainloop()
Il campo della data è in una singola colonna, quindi spinge la colonna successiva a destra.
Aggiorna il blocco della data e aggiungi columnspan=4
date = cur_date()
db_ini_date = tk.Label(master=window,text=date,bg="#57b956")
db_ini_date.configure(font=("Calibri",12))
db_ini_date.grid(row=0,column=0,columnspan=4,sticky="w") # Allow 4 columns for date
Produzione