it-swarm.com.de

tkinter gui layout using frames and grid

Mein GUI-Layout

gui layout

sieht fast nichts aus wie was ich erwarte

what I expect

daher gehe ich davon aus, dass es einige Grundlagen gibt, die ich nicht verstehe.

Ich bin davon ausgegangen, dass Frames ihren eigenen 'Rasterraum' (Zeile, Spalte) enthalten, aber das Verhalten, das ich sehe, bestätigt das nicht und ich bin ratlos, wenn es darum geht, dass die Dinge so funktionieren, wie ich es mir für das obere Frame wünsche. Meine Beschriftungen sollten sich in der gleichen Reihe von L bis R befinden, unter einer Rahmenbeschriftung, die sich über den gesamten Rahmen erstreckt - sofern dies nicht der Fall ist. Ich möchte, dass das tatsächliche Ergebnis eher wie das Ziel-JPG aussieht, und ich möchte das Raster verwenden, um es zu tun.

Sie können nur eines der Eingabefelder rechts vom grünen Rahmen sehen. Warum geht es dorthin?

from Tkinter import *

root = Tk()
root.title('Model Definition')
root.resizable(width=FALSE, height=FALSE)
root.geometry('{}x{}'.format(460, 350))

top_frame = Frame(root, bg='cyan', width = 450, height=50, pady=3).grid(row=0, columnspan=3)
Label(top_frame, text = 'Model Dimensions').grid(row = 0, columnspan = 3)
Label(top_frame, text = 'Width:').grid(row = 1, column = 0)
Label(top_frame, text = 'Length:').grid(row = 1, column = 2)
entry_W = Entry(top_frame).grid(row = 1, column = 1)
entry_L = Entry(top_frame).grid(row = 1, column = 3)
#Label(top_frame, text = '').grid(row = 2, column = 2)

center = Frame(root, bg='gray2', width=50, height=40, padx=3, pady=3).grid(row=1, columnspan=3)
ctr_left = Frame(center, bg='blue', width=100, height=190).grid(column = 0, row = 1, rowspan = 2)
ctr_mid = Frame(center, bg='yellow', width=250, height=190, padx=3, pady=3).grid(column = 1, row=1, rowspan=2)
ctr_right = Frame(center, bg='green', width=100, height=190, padx=3, pady=3).grid(column = 2, row=1, rowspan=2)

btm_frame = Frame(root, bg='white', width = 450, height = 45, pady=3).grid(row = 3, columnspan = 3)
btm_frame2 = Frame(root, bg='lavender', width = 450, height = 60, pady=3).grid(row = 4, columnspan = 3)


root.mainloop()

Also speziell, wo sind meine Labels und Entry-Widgets hingegangen und wie kann ich sie dazu bringen, dem Ziel ähnlicher zu werden (oberster Frame, der Rest ist für später).

20
shawn

Ich nahm an, dass Frames ihren eigenen 'Rasterraum' enthalten

Das ist eine korrekte Annahme.

Sie können nur eines der Eingabefelder rechts vom grünen Rahmen sehen. Warum geht es dorthin?

Das Problem beginnt hier:

top_frame = Frame(root, ...).grid(row=0, ...)

In Python setzt x = y().z() immer x auf das Ergebnis von .z(). Im Fall von top_frame = Frame(...).grid(...) gibt grid(...) immer None zurück, so dass top_frameNone ist. Dies führt dazu, dass jedes Widget, von dem Sie glauben, dass es in den oberen Frame verschoben wird, tatsächlich in das Stammfenster verschoben wird.

Lösungsüberblick

Als allgemeine Faustregel sollten Sie niemals grid, pack oder place als Teil aufrufen der gleichen Anweisung, die das Widget erstellt. Teilweise liegt es an genau diesem Verhalten, das Sie beobachten, aber auch daran, dass es Ihrer Meinung nach schwieriger ist, Ihren Code zu schreiben und im Laufe der Zeit schwieriger zu warten.

Widget-Erstellung und Widget-Layout sind zwei verschiedene Dinge. Nach meiner Erfahrung sind Layoutprobleme erheblich leichter zu debuggen, wenn Sie Ihre Layoutbefehle zusammenfassen.

Außerdem sollten Sie bei der Verwendung des Rasters konsistent sein und die Optionen immer in der gleichen Reihenfolge platzieren, damit Sie das Layout einfacher visualisieren können. Und schließlich sollten Sie sich angewöhnen, bei der Verwendung von grid immer die Option sticky anzugeben und einer Zeile und einer Spalte in jedem enthaltenen Frame eine Gewichtung ungleich Null zuzuweisen.

Lösungsbeispiel

So würde ich Ihren Code schreiben. Es ist viel länger, aber viel einfacher zu verstehen.

from Tkinter import *

root = Tk()
root.title('Model Definition')
root.geometry('{}x{}'.format(460, 350))

# create all of the main containers
top_frame = Frame(root, bg='cyan', width=450, height=50, pady=3)
center = Frame(root, bg='gray2', width=50, height=40, padx=3, pady=3)
btm_frame = Frame(root, bg='white', width=450, height=45, pady=3)
btm_frame2 = Frame(root, bg='lavender', width=450, height=60, pady=3)

# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)

top_frame.grid(row=0, sticky="ew")
center.grid(row=1, sticky="nsew")
btm_frame.grid(row=3, sticky="ew")
btm_frame2.grid(row=4, sticky="ew")

# create the widgets for the top frame
model_label = Label(top_frame, text='Model Dimensions')
width_label = Label(top_frame, text='Width:')
length_label = Label(top_frame, text='Length:')
entry_W = Entry(top_frame, background="pink")
entry_L = Entry(top_frame, background="orange")

# layout the widgets in the top frame
model_label.grid(row=0, columnspan=3)
width_label.grid(row=1, column=0)
length_label.grid(row=1, column=2)
entry_W.grid(row=1, column=1)
entry_L.grid(row=1, column=3)

# create the center widgets
center.grid_rowconfigure(0, weight=1)
center.grid_columnconfigure(1, weight=1)

ctr_left = Frame(center, bg='blue', width=100, height=190)
ctr_mid = Frame(center, bg='yellow', width=250, height=190, padx=3, pady=3)
ctr_right = Frame(center, bg='green', width=100, height=190, padx=3, pady=3)

ctr_left.grid(row=0, column=0, sticky="ns")
ctr_mid.grid(row=0, column=1, sticky="nsew")
ctr_right.grid(row=0, column=2, sticky="ns")

root.mainloop()

Ergebnis:

screenshot of running example

35
Bryan Oakley

variable = Widget(...).grid() weist der Variablen None zu, weil grid()/pack()/place() return None

verwenden

variable = Widget(...)
variable.grid() # .pack() .place()
2
furas