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

7 投票
4 回答
19179 浏览
提问于 2025-04-17 15:42

我的抱怨

我现在正在深入学习Tkinter这个图形用户界面(GUI),发现它的.grid()布局管理器有几个地方不太好用:

  1. 布局是根据里面最大的组件来决定的,这样会导致位置不准确。

  2. 在Windows 7上,使用Python 2.7.3时,程序似乎不太管我设置的行号,而是按照组件的顺序来排列。

我的代码

我现在正在做一个非常简单的文本编辑器,想在窗口顶部放几个按钮。但是我发现我的组件要么被放在屏幕中央巨大文本框的左边,要么右边,无法做到我想要的布局。

========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============

我的问题

有没有其他更准确的方法来使用.grid()布局管理器,或者我应该换个方法来做呢?

谢谢!

4 个回答

1

我觉得 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

不知道为什么,大家似乎不太喜欢 .place 管理器,但我觉得它在定义小部件(也就是你界面上的各种元素)在父窗口调整大小时应该如何移动和调整大小方面做得特别好。

为了方便构建复杂的窗口,有时候我会用一个函数(我想这有点像模拟网格的行为)来帮助垂直放置,比如:

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.

这样可以先放一个标签,然后再放一系列按钮。(当然,在这种情况下也可以使用 .pack 管理器,但我更喜欢 .place 管理器,因为它能让我更准确地理解当窗口调整大小时,东西会如何移动。)

7

选择“最佳”的布局管理器其实要看你想要做什么,没有一种布局管理器适合所有情况。在你这个具体的例子中,使用pack可能是更好的选择。还有一点要注意的是,在一个应用程序中可能会有不止一种“最佳”选择。通常在不同的地方同时使用grid和pack是很正常的。我很少创建一个不同时使用grid和pack的图形用户界面(GUI)。偶尔,我也会用到place。

pack特别适合把东西放在单行或单列中。例如,工具栏就是一个很好的使用pack的例子,因为你希望所有的按钮都对齐在左边。而grid,顾名思义,适合需要固定行和列的情况。place则在grid和pack都不合适的特殊情况下很有用,因为它可以让你把小部件放在精确的固定位置或相对位置。

我的建议是把你的应用程序的小部件分成几个组,然后为每个组使用合适的布局管理器。在你的例子中,有两个逻辑组:顶部的工具栏和底部的文本框加滚动条组合。所以,先创建两个框架。因为工具栏在上面,文本框在下面,使用pack是最合适的。

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

这样一来,你就得到了两个可以独立修改的区域。

对于工具栏,使用pack也是最自然的选择。不过在这种情况下,你希望按钮在左边,而不是在顶部或底部:

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

最后是底部区域。你的示例代码没有显示滚动条,但我假设你最终会想要添加它们。如果你同时使用水平和垂直滚动条,grid会很合适。我会这样布局:

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)

最后一点很重要——你总是需要给至少一行和一列设置权重。这告诉grid在窗口调整大小时,哪些行和列应该扩展或缩小。

16

你可以使用三种布局管理器,分别是 gridpackplace。第三种是最灵活的,但使用起来也比较复杂。我个人更喜欢用 grid。需要注意的是,你可以把小部件放在其他小部件里面,或者你可以指定 columnspan。所以,如果你想要得到下面这样的布局:

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

使用 .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)

*注意,还有一个类似的选项叫 rowspan

第二种方法是使用 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.

这种方法对于创建复杂布局非常有用——我真不知道如果不使用像 Frame 这样的对象,怎么能创建复杂的布局……

撰写回答