【问题标题】:What is a better Tkinter geometry manager than .grid()什么是比 .grid() 更好的 Tkinter 几何管理器
【发布时间】:2013-01-28 13:22:09
【问题描述】:

我的投诉

我目前比以往任何时候都更深入地研究 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() 几何管理器,或者我应该完全使用其他功能?

谢谢!

【问题讨论】:

  • 您关于 windows 没有“注意行号”的评论不正确。几十年来,网格几何管理器已被证明可在所有平台上 100% 正常运行。我并不是说你的代码没有行为不端,只是因为你认为的原因而行为不端。

标签: python tkinter


【解决方案1】:

您可以使用 3 个几何管理器 - 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.

这个方法SUPER对于创建复杂的布局很有用——我不知道你怎么能不使用Frame这样的对象来创建一个复杂的布局......

【讨论】:

  • Ok.... 所以您使用的是 Tk.Canvas 而不是 Tk.Text,对吗?另外,您将如何使用 .place() 以及为什么它是最通用/最准确的(对我来说含义模棱两可)
  • 使用.place,您可以指定要放置小部件的确切坐标。就我而言,这将是一个维护噩梦,几乎不值得一提。 -- 是的,我说的是Canvas 而不是Text -- 我只需要选择一个通常比Button 小部件占用更多空间的小部件;-)
  • +1 - 根据我使用许多不同的 GUI 工具包和几何管理器的经验,使用非常简单的布局管理器并嵌套不同的组是迄今为止效果最好的。所有那些更复杂的几何结构(我说的是 Swing 和所有不同的管理器)都更难使用,并且实际上并没有给你任何嵌套方法无法获得的东西。
  • @Voo -- 我不能说任何其他的 GUI 工具包 -- 我只知道 Tkinter -- 但这一直是我的主力,我看不到任何更好的方法。
  • 至于如何使用 OOP——我不知道。我对使用或不使用 OOP 并不太执着。我只是试图让代码以一种对我有意义的方式工作,并尽可能地清理界面。坐下来弄清楚你希望这些片段如何交互真的很值得——然后,一旦你弄清楚了数据应该如何在程序中传递,通常就更容易设计 GUI。我认为您可以将Tkinter 用于更大的项目。我知道布莱恩·奥克利会同意——但其他人会不同意。例如,较大的项目通常使用 gtk/wxWidgets。
【解决方案2】:

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

pack 擅长将东西放在单行和单列中。例如,工具栏是使用 pack 的完美案例,因为您希望所有按钮都向左对齐。顾名思义,当您需要固定的行和列时,网格是最好的。 place 在 grid 和 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)

最后一部分很重要——您始终需要为至少一行和一列赋予权重。这告诉网格在调整窗口大小时哪些行和列应该增长和缩小。

【讨论】:

    【解决方案3】:

    我发现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 管理器的原因是为了更准确地了解调整窗口大小时事物将如何移动)。

    【讨论】:

    • 我不了解您的 cmets 关于准确性的问题。例如,当我使用 pack 和 grid 时,我准确地知道它们的行为方式。在这方面,地点如何更准确?至于为什么大多数人不使用 place,可能是因为它更复杂:它需要你自己做很多数学运算。 pack 和 grid 都会为您处理大部分数学运算。
    • 我想我喜欢place 的地方只是坐标系。 @Bryan Oakley:从这个意义上说是准确的:我确切地知道我将小部件放在哪里以及在框架内以绝对坐标或相对坐标给出的大小。我可以像这样添加我所有的小部件。我不太喜欢pack 的地方是需要一个不可见的Frames 层次结构来对小部件进行分组。我不太喜欢grid 是在调整窗口大小应该移动小部件但不修改它们的大小时,必须使用“缓冲区”(不可见)行/列来提供可扩展的“填充”。但也许我错过了什么?
    【解决方案4】:

    可以用坐标代替行、列...等。

    这可能比其他的更容易。

    示例:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-27
      • 2023-03-13
      • 2011-01-08
      相关资源
      最近更新 更多