2016-04-08 48 views
2

Ich baue eine GUI für eine Software und will dies erreichen:Tkinter: Gitter oder Pack in einem Gitter?

###################################### 
#    |  some title  # 
# menu upper |----------------------# 
#    |      # 
#    |   CANVAS  # 
# menu lower |      # 
#    |      # 
#------------------------------------# 
#    statusbar    # 
###################################### 

Menü obere hat einige hohe Funktionalität, Menü untere wird in Abhängigkeit von Benutzereingaben zu ändern. Die Statusleiste ändert häufig ihren Inhalt.


Leider weigert sich Tkinter zu arbeiten.

Mit dem Raster-Layout-Manager ich war nicht in der Lage, eine stabile Konstruktion und das Hinzufügen von Inhalten wie Etikett und Tasten, um das Menü auf der linken Seite zu erstellen:

self.root = tk.Tk() 
self.root.resizable(width=0, height=0) 
self.root.title("some application") 

# menu left 
self.menu_left = tk.Frame(self.root, width=150, bg="#ababab") 
self.menu_left.grid(row=0, column=0, rowspan=2, sticky="ns") 

self.menu_left_upper = tk.Frame(self.menu_left, width=150, height=150, bg="red") 
self.menu_left_upper.grid(row=0, column=0) 

# this label breaks the design 
#self.test = tk.Label(self.menu_left_upper, text="test") 
#self.test.pack() 

self.menu_left_lower = tk.Frame(self.menu_left, width=150, bg="blue") 
self.menu_left_lower.grid(row=1, column=0) 

# right area 
self.some_title_frame = tk.Frame(self.root, bg="#dfdfdf") 
self.some_title_frame.grid(row=0, column=1, sticky="we") 

self.some_title = tk.Label(self.some_title_frame, text="some title", bg="#dfdfdf") 
self.some_title.pack() 

self.canvas_area = tk.Canvas(self.root, width=500, height=400, background="#ffffff") 
self.canvas_area.grid(row=1, column=1) 

self.root.mainloop() 

Diesen Entwurf ohne Inhalt im Menü gearbeitet auf der linken Seite. Immer wenn ich etwas in self.menu_left_upper oder self.menu_left_lower, wie das test Etikett, fügte, wurde mein Entwurf pleite: die Menürahmen verschwanden. Zusätzlich, selbst mit Spaltenspanne, musste ich die Statusleiste entfernen, denn als es hinzugefügt wurde, verschwanden die Menüs auf der linken Seite wieder.


Mit Pack Layout-Manager Ich habe dies:

###################################### 
#    |  some title  # 
#    |----------------------# 
# menu upper |      # 
#    |   CANVAS  # 
#    |      # 
# menu lower |      # 
#    |----------------------# 
#    |  statusbar  # 
###################################### 

Da ich den Menürahmen auf der linken Seite wollte die volle y-Raum verbrauchen ich es mit pack(side="left", expand=True, fill="both") wachsen gemacht, aber diese Einstellung verleugnet die Statusleiste immer für die volle Breite.

Außerdem sieht der Pure Pack Manager Code "hässlich". Ich denke ein Design mit einem Grid Manager ist "klarer". Daher dachte ich ein Gitter oder ein Pack-Layout in einem Raster-Layout wäre nett?


Kann jemand helfen? Ich bin in der GUI-Hölle stecken:/

+0

Fragen Sie nach Hilfe mit Grid, oder für Hilfe mit Pack, oder ist es egal, was verwendet wird, solange es das gewünschte Aussehen gibt? Wie sieht 'Pack' Code hässlich aus? Es ist nur Code. –

+0

Es ist mir egal, was verwendet wird, solange es funktioniert. Allerdings würde ich den Grid Manager bevorzugen, da ein Grid Layout für mich sinnvoller ist. Es ist leicht zu verstehen und zu erweitern, während die Verwendung von vielen 'pack()' s mit verschiedenen 'side = ...' Attributen für mich irgendwie verwirrend aussieht. – daniel451

+0

Möchten Sie "Menü obere" und "untere Menü" jeweils 50% der Fläche teilen? –

Antwort

3

Der Schlüssel Layout zu tun, ist methodisch zu sein, und das richtige Werkzeug für den Job zu verwenden. Es bedeutet auch, dass Sie manchmal kreativ sein müssen. Das bedeutet grid zu verwenden, wenn die Dinge aus in einem grid Verlegung und pack zu verwenden, wenn die Dinge aus von oben nach unten oder von links nach rechts legen.

Der andere Schlüssel besteht darin, Ihren Layoutcode zusammenzufassen. Es ist viel, viel einfacher zu visualisieren und das Layout zu ändern, wenn es alles in einem Block Code ist.

In Ihrem Fall scheinen Sie drei oder vier verschiedene Bereiche zu haben, abhängig davon, wie Sie zählen. Wenn Sie Gitter verwenden möchten, ist es am einfachsten, "Menü oberen" und "Menü niedriger" in einem Rahmen zu kombinieren, und behandeln ganzen Rahmen als eine Tabellenzelle. Es sieht so aus als ob du das schon machst, was gut ist.

So lassen Sie uns mit den Hauptbereichen beginnen:

self.menu_left.grid(row=0, column=0, rowspan=2, sticky="nsew") 
self.some_title_frame.grid(row=0, column=1, sticky="ew") 
self.canvas_area.grid(row=1, column=1, sticky="nsew") 
# you don't have a status bar in the example code, but if you 
# did, this is where you would put it 
# self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew") 

Jedes Mal, wenn Sie verwenden grid, benötigen Sie mindestens eine Zeile und eine Säule ein positives Gewicht zu geben, damit tkinter weiß, wo jede verwenden nicht zugeordneten Speicherplatz. Normalerweise gibt es ein Widget, das das "Haupt" Widget ist. In diesem Fall ist es die Leinwand. Sie wollen sicherstellen, dass die Zeile und Spalte für die Leinwand mit einem Gewicht von 1 (eins) hat:

self.root.grid_rowconfigure(1, weight=1) 
self.root.grid_columnconfigure(1, weight=1) 

Anmerkung: pack statt Gitter verwenden würden Sie zwei Codezeilen speichern, da pack nicht Sie müssen Gewichte so einstellen, wie es grid tut.

Als nächstes müssen wir das Problem der Menübereiche lösen. Standardmäßig schrumpfen Frames, um ihren Inhalt anzupassen, weshalb das Hinzufügen des Labels Ihr Layout "kaputt" hat. Sie haben Tkinter nicht gesagt, was Sie mit zusätzlichem Platz tun sollten, also wurden die Rahmen verkleinert und zusätzlicher Platz wurde nicht genutzt.

Da Sie wollen "menu_top" und "menu_bottomn" zu teilen Sie jeweils 50% dieses Bereichs, pack ist die einfachste Lösung. Sie können verwenden grid, aber es erfordert mehr Zeilen Code (um die Gewichte hinzuzufügen).

self.menu_left_upper.pack(side="top", fill="both", expand=True) 
self.menu_left_lower.pack(side="top", fill="both", expand=True) 

Hier ist eine funktionierende Version mit Statusleiste. Beachten Sie, wie, wenn Sie die Größe, es verhält sich genau so, wie es sein sollte:

import Tkinter as tk 

class Example(): 
    def __init__(self): 
     self.root = tk.Tk() 
     self.root.title("some application") 

     # menu left 
     self.menu_left = tk.Frame(self.root, width=150, bg="#ababab") 
     self.menu_left_upper = tk.Frame(self.menu_left, width=150, height=150, bg="red") 
     self.menu_left_lower = tk.Frame(self.menu_left, width=150, bg="blue") 

     self.test = tk.Label(self.menu_left_upper, text="test") 
     self.test.pack() 

     self.menu_left_upper.pack(side="top", fill="both", expand=True) 
     self.menu_left_lower.pack(side="top", fill="both", expand=True) 

     # right area 
     self.some_title_frame = tk.Frame(self.root, bg="#dfdfdf") 

     self.some_title = tk.Label(self.some_title_frame, text="some title", bg="#dfdfdf") 
     self.some_title.pack() 

     self.canvas_area = tk.Canvas(self.root, width=500, height=400, background="#ffffff") 
     self.canvas_area.grid(row=1, column=1) 

     # status bar 
     self.status_frame = tk.Frame(self.root) 
     self.status = tk.Label(self.status_frame, text="this is the status bar") 
     self.status.pack(fill="both", expand=True) 

     self.menu_left.grid(row=0, column=0, rowspan=2, sticky="nsew") 
     self.some_title_frame.grid(row=0, column=1, sticky="ew") 
     self.canvas_area.grid(row=1, column=1, sticky="nsew") 
     self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew") 

     self.root.grid_rowconfigure(1, weight=1) 
     self.root.grid_columnconfigure(1, weight=1) 

     self.root.mainloop() 

Example() 

auf einem nicht verwandten Anmerkung: Ich würde Ihnen dringend ermutigen, nicht die Möglichkeit für den Benutzer entfernen, um die Größe des Fensters. Sie wissen besser als Sie, was ihre Anforderungen sind. Wenn Sie grid und pack richtig verwenden, ändert sich die Größe der GUI perfekt.

+0

Was für ein schönes Tutorial. Dies könnte ein Teil der offiziellen Tkinter-Dokumentation gewesen sein. –

0

den folgenden Code direkt vor self.root.mainloop() Hinzufügen erreicht, was Sie suchen

self.some_status = tk.Label(self.root, text="status bar", bg="#dfdfdf") 
self.some_status.grid(row=3, column=0, columnspan=2, sticky="we") 
+0

True, aber es löst nicht den seltsamen Fehler, dass die Menüleiste links verschwindet, wenn ich dort Inhalte hinzufüge. Wenn ich das tue 'self.test = tk.Label (self.menu_left_upper, text = "test") 'und' self.test.pack() 'oder' self.test.grid() 'das Menü oben/unten an die linke verschwindet. – daniel451

+0

haben Sie versucht, dem 'self.test' Padding (' padx' und 'pady') zu geben? – Kidus

0

von in der Linie setzen:

menu_left_upper.grid_propagate(False) 

Dazwischen und Ihre menu_left_upper Rahmen menu_left_upper.mainloop()

Dies funktioniert wie:

Standardmäßig wird ein Container-Widget so vergrößert oder verkleinert, dass es gerade groß genug ist, um den Inhalt aufzunehmen. Wenn Sie also pack aufrufen, wird der Frame verkleinert. Diese Funktion heißt Geometry Propagation.

Für die überwiegende Mehrheit der Anwendungen ist dies das gewünschte Verhalten.Für die seltenen Fälle, in denen Sie die Größe eines Containers explizit festlegen möchten, können Sie diese Funktion deaktivieren. Um es zu deaktivieren, rufen Sie entweder pack_propagate oder grid_propagate auf dem Container (je nachdem, ob Sie Grid oder Pack für diesen Container verwenden), geben Sie einen Wert von False.

See link to another question where this came from

Um die Statusleiste implementieren nur einen anderen Rahmen und Gitterverfahren zu erhalten:

status_bar_frame = Frame(root, bg="#dfdfdf") 
status_bar_frame.grid(row=3, column=0, columnspan=2, sticky="we") 

status_bar = Label(status_bar_frame, text="status bar", bg="#dfdfdf") 
status_bar.pack() 

Dann arbeitet Ihr Plan. Hoffe es hilft :)

PS. Auch warum alle self Attribute?

EDIT: arbeiten Sie tun müssen:

menu_left_upper = Frame(menu_left, width=225, height=225, bg="red") 
menu_left_upper.grid_propagate(False) 
menu_left_upper.grid(row=0, column=0) 

# this label breaks the design 
test = Label(menu_left_upper, text="test", bg='red') 
test.grid() 

My result

+0

Warum der Downvote? Etwas verwirrt, warum jemand das getan hat ... beantwortet die Frage und bekommt den Plan :( –

+0

Danke, werde das testen. Der Downvote war nicht ich. So erstellen Frames und verwalten sie auf der obersten Ebene mit Grid-Manager, während verwalten Der Inhalt eines Frames mit einem Pack-Manager ist legal? – daniel451

+0

Ich habe versucht, jede mögliche Kombination von '.grid_propagate (False)': dies nur 'menu_left', nur' menu_left_upper', nur 'menu_left_lower' oder Kombinationen davon zuzuweisen. Keiner hat funktioniert. Das Menü und die Subframes werden korrekt angezeigt ** ohne ** Inhalt, aber sobald zB das 'test'-Label zu' menu_left_upper' hinzugefügt wird, verschwindet der Frame. – daniel451