简体   繁体   English

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

[英]What is a better Tkinter geometry manager than .grid()

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! 谢谢!

There are 3 geometry managers that you have available to you -- grid , pack and place . 您可以使用3种几何管理器 - gridpackplace The third is the most general, but also very difficult to use. 第三是最普遍的,但也很难使用。 I prefer grid . 我更喜欢grid Note that you can place widgets inside of other widgets -- Or you can specify columnspan . 请注意,您可以将小部件放在其他小部件中 - 或者您可以指定columnspan So, if you want to get the following layout: 所以,如果你想获得以下布局:

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

there are 2 canonical ways to do it using .grid . 使用.grid有两种规范方法。 The first method is columnspan : 第一种方法是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的对象是这样的...

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. 我很少创建一个GUI,我不使用网格和包。 And rarely, I also use place. 很少,我也使用地方。

pack excels at placing things in single rows and single columns. pack擅长将东西放在单行和单列中。 Toolbars, for example, are a perfect case for using pack since you want all your buttons aligned to the left. 例如,工具栏是使用pack的理想选择,因为您希望所有按钮都对齐到左侧。 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. 在网格和包都不会发生的极少数情况下,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. 这会告诉网格调整窗口大小时哪些行和列应该增长和缩小。

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: 我发现place经理最直观,最准确,因为可以指定位置和大小的绝对长度和相对长度的组合:

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). (当然,在这种情况下可以使用.pack管理器,但我更喜欢.place管理器的原因是为了更准确地理解在调整窗口大小时事物会如何移动)。

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值来尝试自己。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM