什么是比.grid()更好的Tkinter几何管理器

时间:2022-11-11 18:21:51

My Complaint

I am currently delving deeper than "ever" before into the Tkinter GUI, and I have found the .grid() geometry manager to be inadequate for several reasons:

我目前正在深入研究Tkinter GUI之前的“永远”,我发现.grid()几何管理器由于以下几个原因而不合适:

  1. The plots are based on the largest widget within them - this relativity leads to inaccuracy.

    这些图基于其中最大的小部件 - 这种相对性导致不准确。

  2. In Windows 7, on Python 2.7.3, the program does not seem to heed my row numbers, instead preferring to use the order of the widgets.

    在Windows 7中,在Python 2.7.3上,程序似乎没有注意到我的行号,而是更喜欢使用小部件的顺序。

My Code

I am currently working on a really basic text editor, and I want to have multiple buttons on the top of the frame. I have been unable to do this as my widgets are placed either to the far left or right of the massive textbox that dominates the center of the screen.

我目前正在开发一个非常基本的文本编辑器,我想在框架的顶部有多个按钮。我无法做到这一点,因为我的小部件被放置在占据屏幕中心的大量文本框的最左侧或右侧。

========Class __init__ Stuff============
def widget(self):#Place widgets here

    #Save Button
    self.saveButton = Button (self, text = "Save", command = self.saveMe)
    self.saveButton.grid(column = 0, row = 0, sticky = W)

    #Open Button
    self.openButton = Button (self, text = "Open", command = self.openMe)
    self.openButton.grid(column = 0, row = 1, sticky = W)
    #Area where you write 
    self.text = Text (self, width = (root.winfo_screenwidth() - 20),
                      height = (root.winfo_screenheight() - 10))
    self.text.grid(row = 2)
==============Mainloop/Command Stuff============

My Question

Is there another way to use the .grid() geometry manager in a way that is more accurate, or should I be using another function altogether?

是否有另一种方法以更准确的方式使用.grid()几何管理器,或者我应该完全使用另一个函数?

Thanks!

4 个解决方案

#1


14  

There are 3 geometry managers that you have available to you -- grid, pack and place. The third is the most general, but also very difficult to use. I prefer grid. Note that you can place widgets inside of other widgets -- Or you can specify columnspan. So, if you want to get the following layout:

您可以使用3种几何管理器 - 网格,包装和放置。第三是最普遍的,但也很难使用。我更喜欢网格。请注意,您可以将小部件放在其他小部件中 - 或者您可以指定columnspan。所以,如果你想获得以下布局:

  -------------------------
  |    Button1  | Button2 |
  -------------------------
  |     Big Widget        |
  -------------------------

there are 2 canonical ways to do it using .grid. The first method is columnspan:

使用.grid有两种规范方法。第一种方法是columnspan:

import Tkinter as Tk
root = Tk.Tk()
b1 = Tk.Button(root,text="Button1")
b1.grid(row=0,column=0)
b2 = Tk.Button(root,text="Button2")
b2.grid(row=0,column=1)
big_widget = Tk.Canvas(root)
big_widget.grid(row=1,column=0,columnspan=2)

*note that there is a completely analogous rowspan option as well.

*请注意,还有一个完全类似的rowspan选项。

The second method is to use a Frame to hold your buttons:

第二种方法是使用Frame来保存按钮:

import Tkinter as Tk
root = Tk.Tk()
f = Tk.Frame(root)
f.grid(row=0,column=0)
#place buttons on the *frame*
b1 = Tk.Button(f,text="Button1")
b1.grid(row=0,column=0)
b2 = Tk.Button(f,text="Button2")
b2.grid(row=0,column=1)

big_widget = Tk.Canvas(root)
big_widget.grid(row=1,column=0)  #don't need columnspan any more.

This method is SUPER useful for creating complex layouts -- I don't know how you could create a complex layout without using Frame objects like this ...

这个方法对于创建复杂的布局非常有用 - 我不知道如何在不使用像这样的Frame对象的情况下创建复杂的布局...

#2


5  

The "best" geometry manager depends on what you want to do, no geometry manager is best for all situations. For what you're trying to do in this specific case, pack is probably the better choice. Also note that there may be more than one "best" in an application. It's quite normal to use both grid and pack in different parts of your applications. I rarely ever create a GUI where I don't use both grid and pack. And rarely, I also use place.

“最佳”几何管理器取决于您想要做什么,没有几何管理器最适合所有情况。对于您在此特定情况下尝试做的事情,打包可能是更好的选择。另请注意,应用程序中可能有多个“最佳”。在应用程序的不同部分使用网格和包是很正常的。我很少创建一个GUI,我不使用网格和包。很少,我也使用的地方。

pack excels at placing things in single rows and single columns. Toolbars, for example, are a perfect case for using pack since you want all your buttons aligned to the left. grid, as it name implies, is best when you want fixed rows and columns. place is useful in those rare cases where neither grid nor pack will do, since it allows you to place widgets at precise fixed or relative locations.

pack擅长将东西放在单行和单列中。例如,工具栏是使用pack的理想选择,因为您希望所有按钮都对齐到左侧。顾名思义,网格最适合您想要固定的行和列。在网格和包都不会出现的极少数情况下,place非常有用,因为它允许您将小部件放在精确的固定或相对位置。

My advice is to divide your application widgets into groups, and use the right geometry manager for each group. In your case you have two logical groups: the toolbar along the top, and a text-widget-and-scrollbar combination in the bottom. So, start with two frames. Since the toolbar is on top and the text widget is below, pack works best.

我的建议是将应用程序小部件分成组,并为每个组使用正确的几何管理器。在您的情况下,您有两个逻辑组:顶部的工具栏,以及底部的文本小部件和滚动条组合。所以,从两帧开始。由于工具栏位于顶部,文本小部件位于下方,因此打包效果最佳。

toolbar = tk.Frame(...)
main = tk.Frame(...)
toolbar.pack(side="top", fill="x", expand=False)
main.pack(side="bottom", fill="both", expand=True)

The above now gives you two areas that are easy to modify independently.

以上现在为您提供了两个易于独立修改的区域。

For the toolbar, pack is again most natural. In this case, however, you want the buttons along the left instead of along the top or bottom:

对于工具栏,包装也是最自然的。但是,在这种情况下,您需要左侧的按钮而不是顶部或底部的按钮:

b1 = tk.Button(toolbar, ...)
b2 = tk.Button(toolbar, ...)
b1.pack(side="left")
b2.pack(side="left")
...

Finally, the bottom area. Your example code doesn't show scrollbars, but I assume at some point you'll want to add them. grid works well if you're using both horizontal and vertical scrollbars. I would lay them out like this:

最后,底部区域。您的示例代码不显示滚动条,但我认为在某些时候您会想要添加它们。如果你同时使用水平和垂直滚动条,网格效果很好。我会这样说出来:

hsb = tk.Scrollbar(main, ..., orient="horizontal", ...)
vsb = tk.Scrollbar(main, ..., orient="vertical", ...)
text = tk.Text(main, ...)
vsb.grid(row=0, column=1, sticky="ns")
hsb.grid(row=1, column=0, sticky="ew")
text.grid(row=0, column=0, sticky="nsew")
main.grid_rowconfigure(0, weight=1)
main.grid_columnconfigure(0, weight=1)

That last part is important -- you always need to give a weight to at least one row and one column. This tells grid which rows and columns should grow and shrink when the window is resized.

最后一部分很重要 - 你总是需要给至少一行和一列赋予权重。这会告诉网格调整窗口大小时哪些行和列应该增长和缩小。

#3


0  

I find the place manager the most intuitive and accurate of all three, because of the possibility to specify combinations of absolute and relative lengths for both positions and size:

我发现场所管理者最直观,最准确,因为可以指定位置和大小的绝对长度和相对长度的组合:

mywidget.place(x=..., y=..., width=..., height=...) # absolute
mywidget.place(relx=..., rely=..., relwidth=..., relheight=...) # relative

# combination
pad_left=5
pad_right=5
pad_top=5
pad_bottom=5
mywidget.place(relx=0, x=pad_left, rely=0, y=pad_top,\
       relwidth=1, width=-pad_left-pad_right,\
       relheight=1, height=-pad_top-pad_bottom, anchor="e") # use the whole space except some padding

For some reason, the .place manager doesn't seem very liked, but I find it makes a particulary good job to define how your widgets should move around and resize when the parent window is resized.

出于某种原因,.place管理员似乎并不是很受欢迎,但我发现定义你的小部件如何移动并在调整父窗口大小时调整大小是一项特别好的工作。

To ease the construction of complex windows, I sometimes use a function (to kind of emulate a grid behaviour I suppose) to aid in the vertical placement, such as:

为了简化复杂窗口的构造,我有时会使用一个函数(以模仿我想的网格行为)来帮助垂直放置,例如:

def offset_y(line_no):
    if line_no == 0:
        return 0
    else:
        return height_label + (line_no - 1)*height_button

mylabel.place(..., y=offset_y(0))
mybtn1.place(..., y=offset_y(1))
etc.

to pack vertically a Label and then a series of buttons. (Of course, the .pack manager could be used in this case, but the reason I prefer the .place manager is for understanding more accurately how things will move around when the window is resized).

垂直打包Label,然后是一系列按钮。 (当然,在这种情况下可以使用.pack管理器,但我更喜欢.place管理器的原因是为了更准确地理解在调整窗口大小时事物会如何移动)。

#4


-2  

Instead of row,column....etc.,you can use coordinates.

而不是行,列......等,您可以使用坐标。

It may be easier than the others.

它可能比其他人容易。

EXAMPLE:

from Tkinter import*
root=Tk()
Button(root,text="HI").grid(padx=100,pady=50)
root.mainloop()

Try it youself by changing padx and pady values.

通过更改padx和pady值来尝试自己。

#1


14  

There are 3 geometry managers that you have available to you -- grid, pack and place. The third is the most general, but also very difficult to use. I prefer grid. Note that you can place widgets inside of other widgets -- Or you can specify columnspan. So, if you want to get the following layout:

您可以使用3种几何管理器 - 网格,包装和放置。第三是最普遍的,但也很难使用。我更喜欢网格。请注意,您可以将小部件放在其他小部件中 - 或者您可以指定columnspan。所以,如果你想获得以下布局:

  -------------------------
  |    Button1  | Button2 |
  -------------------------
  |     Big Widget        |
  -------------------------

there are 2 canonical ways to do it using .grid. The first method is columnspan:

使用.grid有两种规范方法。第一种方法是columnspan:

import Tkinter as Tk
root = Tk.Tk()
b1 = Tk.Button(root,text="Button1")
b1.grid(row=0,column=0)
b2 = Tk.Button(root,text="Button2")
b2.grid(row=0,column=1)
big_widget = Tk.Canvas(root)
big_widget.grid(row=1,column=0,columnspan=2)

*note that there is a completely analogous rowspan option as well.

*请注意,还有一个完全类似的rowspan选项。

The second method is to use a Frame to hold your buttons:

第二种方法是使用Frame来保存按钮:

import Tkinter as Tk
root = Tk.Tk()
f = Tk.Frame(root)
f.grid(row=0,column=0)
#place buttons on the *frame*
b1 = Tk.Button(f,text="Button1")
b1.grid(row=0,column=0)
b2 = Tk.Button(f,text="Button2")
b2.grid(row=0,column=1)

big_widget = Tk.Canvas(root)
big_widget.grid(row=1,column=0)  #don't need columnspan any more.

This method is SUPER useful for creating complex layouts -- I don't know how you could create a complex layout without using Frame objects like this ...

这个方法对于创建复杂的布局非常有用 - 我不知道如何在不使用像这样的Frame对象的情况下创建复杂的布局...

#2


5  

The "best" geometry manager depends on what you want to do, no geometry manager is best for all situations. For what you're trying to do in this specific case, pack is probably the better choice. Also note that there may be more than one "best" in an application. It's quite normal to use both grid and pack in different parts of your applications. I rarely ever create a GUI where I don't use both grid and pack. And rarely, I also use place.

“最佳”几何管理器取决于您想要做什么,没有几何管理器最适合所有情况。对于您在此特定情况下尝试做的事情,打包可能是更好的选择。另请注意,应用程序中可能有多个“最佳”。在应用程序的不同部分使用网格和包是很正常的。我很少创建一个GUI,我不使用网格和包。很少,我也使用的地方。

pack excels at placing things in single rows and single columns. Toolbars, for example, are a perfect case for using pack since you want all your buttons aligned to the left. grid, as it name implies, is best when you want fixed rows and columns. place is useful in those rare cases where neither grid nor pack will do, since it allows you to place widgets at precise fixed or relative locations.

pack擅长将东西放在单行和单列中。例如,工具栏是使用pack的理想选择,因为您希望所有按钮都对齐到左侧。顾名思义,网格最适合您想要固定的行和列。在网格和包都不会出现的极少数情况下,place非常有用,因为它允许您将小部件放在精确的固定或相对位置。

My advice is to divide your application widgets into groups, and use the right geometry manager for each group. In your case you have two logical groups: the toolbar along the top, and a text-widget-and-scrollbar combination in the bottom. So, start with two frames. Since the toolbar is on top and the text widget is below, pack works best.

我的建议是将应用程序小部件分成组,并为每个组使用正确的几何管理器。在您的情况下,您有两个逻辑组:顶部的工具栏,以及底部的文本小部件和滚动条组合。所以,从两帧开始。由于工具栏位于顶部,文本小部件位于下方,因此打包效果最佳。

toolbar = tk.Frame(...)
main = tk.Frame(...)
toolbar.pack(side="top", fill="x", expand=False)
main.pack(side="bottom", fill="both", expand=True)

The above now gives you two areas that are easy to modify independently.

以上现在为您提供了两个易于独立修改的区域。

For the toolbar, pack is again most natural. In this case, however, you want the buttons along the left instead of along the top or bottom:

对于工具栏,包装也是最自然的。但是,在这种情况下,您需要左侧的按钮而不是顶部或底部的按钮:

b1 = tk.Button(toolbar, ...)
b2 = tk.Button(toolbar, ...)
b1.pack(side="left")
b2.pack(side="left")
...

Finally, the bottom area. Your example code doesn't show scrollbars, but I assume at some point you'll want to add them. grid works well if you're using both horizontal and vertical scrollbars. I would lay them out like this:

最后,底部区域。您的示例代码不显示滚动条,但我认为在某些时候您会想要添加它们。如果你同时使用水平和垂直滚动条,网格效果很好。我会这样说出来:

hsb = tk.Scrollbar(main, ..., orient="horizontal", ...)
vsb = tk.Scrollbar(main, ..., orient="vertical", ...)
text = tk.Text(main, ...)
vsb.grid(row=0, column=1, sticky="ns")
hsb.grid(row=1, column=0, sticky="ew")
text.grid(row=0, column=0, sticky="nsew")
main.grid_rowconfigure(0, weight=1)
main.grid_columnconfigure(0, weight=1)

That last part is important -- you always need to give a weight to at least one row and one column. This tells grid which rows and columns should grow and shrink when the window is resized.

最后一部分很重要 - 你总是需要给至少一行和一列赋予权重。这会告诉网格调整窗口大小时哪些行和列应该增长和缩小。

#3


0  

I find the place manager the most intuitive and accurate of all three, because of the possibility to specify combinations of absolute and relative lengths for both positions and size:

我发现场所管理者最直观,最准确,因为可以指定位置和大小的绝对长度和相对长度的组合:

mywidget.place(x=..., y=..., width=..., height=...) # absolute
mywidget.place(relx=..., rely=..., relwidth=..., relheight=...) # relative

# combination
pad_left=5
pad_right=5
pad_top=5
pad_bottom=5
mywidget.place(relx=0, x=pad_left, rely=0, y=pad_top,\
       relwidth=1, width=-pad_left-pad_right,\
       relheight=1, height=-pad_top-pad_bottom, anchor="e") # use the whole space except some padding

For some reason, the .place manager doesn't seem very liked, but I find it makes a particulary good job to define how your widgets should move around and resize when the parent window is resized.

出于某种原因,.place管理员似乎并不是很受欢迎,但我发现定义你的小部件如何移动并在调整父窗口大小时调整大小是一项特别好的工作。

To ease the construction of complex windows, I sometimes use a function (to kind of emulate a grid behaviour I suppose) to aid in the vertical placement, such as:

为了简化复杂窗口的构造,我有时会使用一个函数(以模仿我想的网格行为)来帮助垂直放置,例如:

def offset_y(line_no):
    if line_no == 0:
        return 0
    else:
        return height_label + (line_no - 1)*height_button

mylabel.place(..., y=offset_y(0))
mybtn1.place(..., y=offset_y(1))
etc.

to pack vertically a Label and then a series of buttons. (Of course, the .pack manager could be used in this case, but the reason I prefer the .place manager is for understanding more accurately how things will move around when the window is resized).

垂直打包Label,然后是一系列按钮。 (当然,在这种情况下可以使用.pack管理器,但我更喜欢.place管理器的原因是为了更准确地理解在调整窗口大小时事物会如何移动)。

#4


-2  

Instead of row,column....etc.,you can use coordinates.

而不是行,列......等,您可以使用坐标。

It may be easier than the others.

它可能比其他人容易。

EXAMPLE:

from Tkinter import*
root=Tk()
Button(root,text="HI").grid(padx=100,pady=50)
root.mainloop()

Try it youself by changing padx and pady values.

通过更改padx和pady值来尝试自己。