[英]How to layout widgets in a Python Tkinter frame under a root TopLevel
Here is the code: 这是代码:
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()
Here is the output: 这是输出:
My Label and Entry both do not show up. 我的标签和条目都没有出现。
I have found that Radiobutton do not have self. 我发现Radiobutton没有自我。 and Label and Entry have it.
和标签和条目有它。
However, I don't know why this will cause the result. 但是,我不知道为什么会导致结果。
Update 更新
I had suggested 2 approaches to solve this. 我提出了两种方法来解决这个问题。 First one is to use the
root
Tk object as the parent for all the widgets; 第一个是使用
root
Tk对象作为所有小部件的父对象; Second is to add the widgets to Window
, and add Window
object to the layout manager of the root
. 其次是将窗口小部件添加到
Window
,并将Window
对象添加到root
的布局管理器。 As Bryan Oakley mentioned (correctly) in the comments, the first approach is not as good (although it works, but still). 正如Bryan Oakley在评论中(正确地)提到的那样,第一种方法并不是那么好(尽管它有效,但仍然如此)。 So I'm suggesting to use the second approach (discussed below), which is:
所以我建议使用第二种方法(下面讨论),即:
Make sure all the widgets ( Radiobutton
, Label
, Entry
, etc.) are using the Window
object (referenced by self
) as the parent, and then add the window instance to the layout manager of the root
. 确保所有小部件(
Radiobutton
, Label
, Entry
等)都使用Window
对象(由self
引用)作为父对象,然后将窗口实例添加到root
的布局管理器中。 Either in init_window
call, or after creating the object. 在
init_window
调用中,或在创建对象之后。
Approach 1 方法1
The widgets under the Window
, should use self
as the parent (to preserve hierarchy), and the Window
itself, should be added to layout manager of master
. Window
下的小部件应该使用self
作为父级(保留层次结构),而Window
本身应该添加到master
布局管理器中。 This way all the widgets will show correctly 这样所有小部件都将正确显示
You should have passed the Tk object (referenced by root
) when adding the widgets to the layout (in this case the grid
geometry). 在将小部件添加到布局(在本例中为
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()
Note that the parent (first argument passed to Label
and Entry
constructors), are changed from self
to self.master
. 请注意,父(传递给
Label
和Entry
构造函数的第一个参数)从self
更改为self.master
。
Also the parent for Radiobutton
are also changed from root
to self.master
, because then root
is a reference to the global variable, and not the actual parent set for Window
object. Radiobutton
的父级也从root
更改为self.master
,因为root
是对全局变量的引用,而不是Window
对象的实际父级。
Update (description) 更新(描述)
The code on the question is adding the Label
and Entry
widgets to self
(the Window
object), so when calling grid
on them it's using the grid
layout of the window object . 问题的代码是将
Label
和Entry
小部件添加到self
( Window
对象),因此当在它们上调用grid
时,它使用窗口对象的grid
布局。 But the window object itself, was not added to the root (Tk)
, so basically the window
object and it's attached widgets would not show at all. 但是窗口对象本身并未添加到
root (Tk)
,因此基本上window
对象及其附加的窗口小部件根本不会显示。
The Radiobutton
instances however, were attached to root
, so calling grid
on them would add them to layout manager of the root (Tk)
, that's why they were showing. 然而,
Radiobutton
实例被附加到root
,因此在它们上面调用grid
会将它们添加到root (Tk)
布局管理器中,这就是它们显示的原因。
One fix for this, is to keep using root
as the parent for all widgets, which causes the window object to be like a data container, but not a widget on the UI. 对此的一个解决方法是继续使用
root
作为所有窗口小部件的父窗口,这会导致窗口对象像数据容器,但不是UI上的窗口小部件。
Approach 2 方法2
Add the window object itself to the layout manager of the root
. 将窗口对象本身添加到
root
的布局管理器。 Something like this: 像这样的东西:
#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
But remember that if you'd like to use this approach (using the window object as a Widget container as well), then again I'd suggest that all the Radiobutton
to use self
(the window object) as their parents instead of root
. 但请记住,如果你想使用这种方法(使用窗口对象作为Widget容器),那么我再次建议所有
Radiobutton
使用self
(窗口对象)作为他们的父母而不是root
。 Because when using root
as the parent, calling grid(row=0, column=0)
on radio buttons, they would be using the same row/column that the window object (frame) is using. 因为当使用
root
作为父节点时,在单选按钮上调用grid(row=0, column=0)
,它们将使用窗口对象(框架)正在使用的相同行/列。
app
is an instance of Window
. app
是Window
一个实例。 Window
is a Frame
. Window
是一个Frame
。 The widgets created by init_window
sometimes have self
as the parent, and sometimes root
. init_window
创建的小部件有时会将self
作为父级,有时则是root
。 The first thing you need to fix is that they all need to have a parent of self
. 你需要解决的第一件事情是,它们都需要有家长
self
。 The point of this sort of design, which you've no doubt copied from somewhere, is that everything inside this class should be contained in this frame. 这种设计的意义,你毫无疑问是从某个地方复制过来的,这个类中的所有东西都应该包含在这个框架中。
Because app
is an instance of Window
and Window
is a subclass of Frame
, everything that goes in this widget will be invisible unless app
is visible. 由于
app
是一个实例Window
和Window
是的子类Frame
,在这个小部件去将是无形的,除非一切app
是可见的。 So, the second part of the solution is to make app
visible. 因此,解决方案的第二部分是使
app
可见。 You can do this however you want. 你可以随心所欲地做到这一点。 In this particular case, since it's the only widget in the root window, I would use pack:
在这种特殊情况下,由于它是根窗口中唯一的小部件,我会使用pack:
app = Window(root)
app.pack(fill="both", expand=True)
You're making the label and entry their own parents and not starting their own event loops. 你正在制作标签并输入他们自己的父母,而不是开始他们自己的事件循环。 Instead of
self
, try changing their parent to root
. 而不是
self
,尝试将其父级更改为root
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.