[英]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.