2017-03-11 4 views
0

Ich muss tkinter Bibliothek verwenden, um GUI zu erstellen.Spezifisches Problem mit Pack beim Erstellen eines Layouts

Ich habe diesen Code:

# -*- coding: UTF-8 -*- 
import tkinter as tk 

class Application(tk.Frame): 

    resx=1600 
    resy=900 

    def __init__(self, master=None): 
     tk.Frame.__init__(self, master) 
     self.pack(fill="both", expand=1) 
     self.createWidgets() 
     master.minsize(self.resx, self.resy) 
     master.maxsize(self.resx, self.resy) 

    def createWidgets(self): 
     self.hi_there = tk.Button(self) 
     self.hi_there["text"] = "Create new window" 
     self.hi_there["command"] = self.PlayMode 
     self.hi_there.pack(side="top") 

    def ShowMenu(self, master): 
     print("Here I need DELETE master, in my case PlayM") 

    def PlayMode(self): 
     PlayM = tk.Tk() 
     PlayM.minsize(self.resx, self.resy) 
     PlayM.maxsize(self.resx, self.resy) 
     PlayM.title("Game") 

     bf= tk.Frame(PlayM, bg="blue") 
     bf.pack(side="bottom", fill=tk.X, expand = 1) 
     lbTEST=tk.Label(bf) 
     lbTEST["text"] = "TESTING" 
     lbTEST.pack() 

     mf = tk.Frame(PlayM,bg="red") 
     mf.pack(side="right", fill=tk.Y, expand=1) 
     self.LogOut = tk.Button(mf) 
     self.LogOut["text"] = "LOGOUT" 
     self.LogOut.pack() 
     self.LogOut["command"] = self.ShowMenu(PlayM) 

root = tk.Tk() 
app = Application(master=root) 
app.master.title("Useless think") 
app.mainloop() 

ich so etwas wie dieses Bild brauchen:

enter image description here

Ich weiß nicht, warum mein Code funktioniert nicht. Wenn ich meine bf (unterer Rahmen) packe und side = "bottom" einstelle, erscheint es aber in der Mitte des Bildschirms. Warum? Gleich mit side = "right" wenn ich packe mf (Menürahmen)

Und ich habe noch eine Frage. Über die Abmelde-Schaltfläche. Ich setze die Methode des Befehls "ShowMenu".

Wenn ich meinen Code ausführen, wird diese Methode automatisch nur einmal gestartet, aber wenn ich auf den Button klicken passiert nichts. Warum?

Antwort

2

Zunächst haben Sie einen kritischen Fehler in Ihrem Code. Sie sollten nicht mehr als eine Instanz von Tk erstellen. Wenn Sie zusätzliche Fenster erstellen müssen, erstellen Sie Instanzen von Toplevel.

Wenn ich meine bf (unteren Rahmen) packen und Seite = "unten" einstellen, aber es erscheint in der Mitte des Bildschirms. Warum?

Sie setzten expand-1 für beide mf und mf so wird jeder in dem Fenster der Hälfte des zur Verfügung stehenden Raumes am Ende unter. Wenn Sie einfach expand auf 0 (Null) oder False für bf setzen, wird nur so viel Platz benötigt wie nötig.

bf.pack(side="bottom", fill=tk.X, expand = 0) 

Als allgemeine Regel sollten Sie nur einen wahren Wert für expand auf einem einzigen Widget (der „Held“ widget) gesetzt, es sei denn, Sie zu gleichen Teilen unter Widgets zusätzlichen Platz verteilen möchten.

Wenn ich meinen Code ausführen, wird diese Methode automatisch nur einmal gestartet, aber wenn ich auf Schaltfläche klicke, passiert nichts. Warum?

Weil Sie es sagen, um zu laufen. Werfen Sie einen Blick auf diesen Code:

self.LogOut["command"] = self.ShowMenu(PlayM) 

Es ist genau das gleiche wie dieser Code:

result = self.ShowMenu(PlayM) 
self.logOut["command"] = result 

das Problem?

Das Attribut command erfordert eine Referenz zu einer Funktion. Grob übersetzt bedeutet das, dass Sie () nicht verwenden können. Wenn Sie in einem Argument für den Befehl übergeben müssen, ist die typische Lösung functools.partial oder lambda zu verwenden, um eine Referenz auf eine anonyme Funktion zu erstellen, die die eigentliche Funktion mit dem Argument nennen:

self.logOut["command"] = lambda arg=PlayM: self.ShowMenu(arg) 
+0

wie immer antwortet Bryan besser als ich ;-) – R4PH43L

+0

Besonderen Dank an Bryan und alle anderen;) Alle Antworten auf meine Frage waren sehr hilfreich. Ich möchte noch eine Frage stellen. Tut jemand tkinter Bibliothek im "wirklichen Leben"? Oder es ist nur "Universitätssprache" (nur für Schüler). Ich frage, weil ich manchmal Probleme habe, eine solide Dokumentation zu finden. – DoctorCZE

+0

@DoctorCZE Ich würde sagen, dass tkinter aus meiner Sicht nützlich ist, um über das Erstellen von GUI (im Allgemeinen) und das schnelle Prototyping einfacher UIs, vielleicht für persönliche Projekte, zu lernen. Ich glaube nicht, dass Tkinter heutzutage von Unternehmen genutzt wird, da es moderne ("bessere") Alternativen gibt, zum Beispiel Kivy, und weil heutzutage UIs dazu neigen, zum Browser gedrängt zu werden. – nbro

1

Gibt es einen bestimmten Grund, warum Sie Pack-Methode anstelle von Gitter verwenden?

Sie können Ihre Anwendungsrahmen wie konfigurieren:

self.grid_rowconfigure(0, weight=1) #make the first "upper" row expand 
self.grid_rowconfigure(1, weight=0) #leave the second "lower" row and do not expand it 

self.grid_columnconfigure(0, weight=0) # first column, do not expand 
self.grid_columnconfigure(1, weight=1) # second columnd, DO expand 
self.grid_columnconfigure(0, weight=0) # third column, do not expand 

auf Ihrem Mainframe/Anwendungsklasse und dann rufen:

bf.grid(row=1, column=0, columnspan=3, sticky=tk.NW+tk.SE) # span over three columns 
lf.grid(row=0, column=0, sticky=tk.NW+tk.SE) # default is to span over one column 
rf.grid(row=0, column=2, sticky=tk.NW+tk.SE) 

bearbeiten

Ich bin sehr traurig, ich habe vergessen um über den Logout-Button zu sprechen. Sie rufen den Event-Handler zum Zeitpunkt der Bindung auf, daher wird er dort ausgeführt.

Wenn Sie es Werte übergeben haben wollen entweder Gebrauch:

  • Befehl = Lambda parent = PlayM: self.ShowMenu (Eltern)
  • ein Klasse-Objekt verwenden, youre geordnete Referenz bei der Erstellung zu speichern self._Parent = PlayM und verwenden Sie dies in ShowMenu

Ich persönlich bevorzuge die Speicherung von Objekten für einzelne Werte. Wenn Sie viele Fenster zu zerstören haben, würde ich das Lambda verwenden.

1

Abgesehen von den Problemen bereits erwähnt von Bryan Oakley und die Lösung von R4PH43L mit grid, hier ist eine mögliche Lösung für Ihr Layout nur mit pack.

Die Idee ist, dass side="left" unter Verwendung von (oder side="right") und dann side="top" (oder side="bottom") nicht die Art und Weise arbeiten Sie erwarten können. innerhalb eines Rahmens sein, sollten Sie nur Werte für side verwenden (wenn Sie die Widgets im selben Frame Packing), die entweder vertikal sind ("top" oder "bottom") oder horizontal ("right" oder "left"), aber nicht beide. Um Layouts wie Ihre zu erstellen, die nur pack verwenden, benötigen Sie zusätzliche Frames!

# -*- coding: UTF-8 -*- 
import tkinter as tk 

class Application(tk.Frame): 

    resx=400 
    resy=200 

    def __init__(self, master=None): 
     tk.Frame.__init__(self, master, bg="red") 
     self.pack(fill="both", expand=1) 
     self.create_widgets() 
     master.geometry("400x200+100+500") 

    def create_widgets(self): 
     self.hi_there = tk.Button(self) 
     self.hi_there["text"] = "Create new window" 
     self.hi_there["command"] = self.play_mode 
     self.hi_there.pack(side="top") 

    def show_menu(self, master): 
     print("Here I need DELETE master, in my case play_m") 

    def play_mode(self): 
     # Using a Toplevel instead of a Tk 
     # You should have just one Tk in your app 
     play_m = tk.Toplevel() 
     play_m.geometry("400x200+100+500") 
     play_m.title("Game") 

     top_frame = tk.Frame(play_m, bg="blue")  
     top_frame.pack(side="top", fill="both", expand=True) 

     left_top_frame = tk.Frame(top_frame, bg="white") 
     left_top_frame_label = tk.Label(left_top_frame, text="left top frame") 
     left_top_frame_label.pack() 
     left_top_frame.pack(side="left", fill="y") 

     middle_top_frame = tk.Frame(top_frame, bg="black") 

     middle_top_frame_button = tk.Button(middle_top_frame, text="Logout", command=play_m.destroy) 
     middle_top_frame_button.pack() 
     middle_top_frame.pack(side="left", fill="both", expand=True) 

     right_top_frame = tk.Frame(top_frame, bg="white") 
     right_top_frame_label = tk.Label(right_top_frame, text="right top frame") 
     right_top_frame_label.pack() 
     right_top_frame.pack(side="right", fill="y") 

     bottom_frame = tk.Frame(play_m, bg="yellow") 
     bottom_frame_label = tk.Label(bottom_frame, text="bottom frame") 
     bottom_frame_label.pack()   
     bottom_frame.pack(side="top", fill="both") 


root = tk.Tk() 
app = Application(master=root) 
app.master.title("Useless think") 
app.mainloop() 

Hier ist das Ergebnis des Haupt Tk Fenster auf einem OS X (Sierra):

enter image description here

Zweite Toplevel

enter image description here

ich die Größen ein wenig verändert um der Darstellung willen. Ich habe auch die Methoden umbenannt, _ und Kleinbuchstaben zu verwenden.

Verwandte Themen