[英]How to layout widgets in a Python Tkinter frame under a root TopLevel
這是代碼:
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title('GUI')
row = 0
self.s_date_label = Label(self, text = 'Start Date: ')
self.s_date_label.grid(row=row, column=0, sticky = W)
self.start_date = Entry(self, bd=1)
self.start_date.grid(row=row, column=1, sticky = W)
self.s_date_label2 = Label(self, text = 'example: 20160101')
self.s_date_label2.grid(row=row, column=2, sticky = W)
self.datetype_var = IntVar()
R1 = Radiobutton(root, text="20160101", variable=self.datetype_var, value=8)
R1.grid(row=row, column=1, sticky = W)
R1.select()
R2 = Radiobutton(root, text="201601", variable=self.datetype_var, value=6)
R2.grid(row=row, column=2, sticky = W)
R3 = Radiobutton(root, text="2016", variable=self.datetype_var, value=4)
R3.grid(row=row, column=3, sticky = W)
root = Tk()
root.geometry('600x400')
app = Window(root)
root.mainloop()
這是輸出:
我的標簽和條目都沒有出現。
我發現Radiobutton沒有自我。 和標簽和條目有它。
但是,我不知道為什么會導致結果。
更新
我提出了兩種方法來解決這個問題。 第一個是使用root
Tk對象作為所有小部件的父對象; 其次是將窗口小部件添加到Window
,並將Window
對象添加到root
的布局管理器。 正如Bryan Oakley在評論中(正確地)提到的那樣,第一種方法並不是那么好(盡管它有效,但仍然如此)。 所以我建議使用第二種方法(下面討論),即:
確保所有小部件( Radiobutton
, Label
, Entry
等)都使用Window
對象(由self
引用)作為父對象,然后將窗口實例添加到root
的布局管理器中。 在init_window
調用中,或在創建對象之后。
方法1
Window
下的小部件應該使用self
作為父級(保留層次結構),而Window
本身應該添加到master
布局管理器中。 這樣所有小部件都將正確顯示
在將小部件添加到布局(在本例中為grid
幾何)時,您應該已經傳遞了Tk對象(由root
引用)。
from Tkinter import *
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title('GUI')
row = 0
self.s_date_label = Label(self.master, text = 'Start Date: ')
self.s_date_label.grid(row=row, column=0, sticky = W)
self.start_date = Entry(self.master, bd=1)
self.start_date.grid(row=row, column=1, sticky = W)
self.s_date_label2 = Label(self.master, text = 'example: 20160101')
self.s_date_label2.grid(row=row, column=2, sticky = W)
self.datetype_var = IntVar()
R1 = Radiobutton(self.master, text="20160101", variable=self.datetype_var, value=8)
R1.grid(row=row, column=1, sticky = W)
R1.select()
R2 = Radiobutton(self.master, text="201601", variable=self.datetype_var, value=6)
R2.grid(row=row, column=2, sticky = W)
R3 = Radiobutton(self.master, text="2016", variable=self.datetype_var, value=4)
R3.grid(row=row, column=3, sticky = W)
root = Tk()
root.geometry('600x400')
app = Window(root)
root.mainloop()
請注意,父(傳遞給Label
和Entry
構造函數的第一個參數)從self
更改為self.master
。
Radiobutton
的父級也從root
更改為self.master
,因為root
是對全局變量的引用,而不是Window
對象的實際父級。
更新(描述)
問題的代碼是將Label
和Entry
小部件添加到self
( Window
對象),因此當在它們上調用grid
時,它使用窗口對象的grid
布局。 但是窗口對象本身並未添加到root (Tk)
,因此基本上window
對象及其附加的窗口小部件根本不會顯示。
然而, Radiobutton
實例被附加到root
,因此在它們上面調用grid
會將它們添加到root (Tk)
布局管理器中,這就是它們顯示的原因。
對此的一個解決方法是繼續使用root
作為所有窗口小部件的父窗口,這會導致窗口對象像數據容器,但不是UI上的窗口小部件。
方法2
將窗口對象本身添加到root
的布局管理器。 像這樣的東西:
#all the code is the same as the question
# ...
app = Window(root)
app.grid(row=0, column=0, sticky=NW)
# the rest of the code
但請記住,如果你想使用這種方法(使用窗口對象作為Widget容器),那么我再次建議所有Radiobutton
使用self
(窗口對象)作為他們的父母而不是root
。 因為當使用root
作為父節點時,在單選按鈕上調用grid(row=0, column=0)
,它們將使用窗口對象(框架)正在使用的相同行/列。
app
是Window
一個實例。 Window
是一個Frame
。 init_window
創建的小部件有時會將self
作為父級,有時則是root
。 你需要解決的第一件事情是,它們都需要有家長self
。 這種設計的意義,你毫無疑問是從某個地方復制過來的,這個類中的所有東西都應該包含在這個框架中。
由於app
是一個實例Window
和Window
是的子類Frame
,在這個小部件去將是無形的,除非一切app
是可見的。 因此,解決方案的第二部分是使app
可見。 你可以隨心所欲地做到這一點。 在這種特殊情況下,由於它是根窗口中唯一的小部件,我會使用pack:
app = Window(root)
app.pack(fill="both", expand=True)
你正在制作標簽並輸入他們自己的父母,而不是開始他們自己的事件循環。 而不是self
,嘗試將其父級更改為root
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.