【问题标题】:Why is inner padding only applied on the right?为什么内部填充只应用于右侧?
【发布时间】:2020-02-20 03:12:52
【问题描述】:

MCVE

import Tkinter as tk
import ttk

root = tk.Tk()
root.minsize(200, 100)
inner_frame = ttk.LabelFrame(root, text='inner_frame')
inner_frame.grid(row=0, column=0)

button = ttk.Button(inner_frame, text='this is a button')
button.grid(row=0, column=0)

# this does not work as expected
inner_frame.grid_configure(ipadx=20)

root.mainloop()

输出

问题

为什么inner_frame 的内边距只应用在右边?两面怎么涂?

【问题讨论】:

    标签: python python-2.7 tkinter


    【解决方案1】:

    在您的情况下,ipadx 并没有失败。它按设计工作,只是它的工作方式不是很直观,尤其是当您将其应用于框架时。

    为了更好地可视化正在发生的事情,让我们将ipadx 值应用于按钮而不是框架。这样我们就可以看到相对于按钮标签的填充。

    例如,添加两个按钮而不是一个。给一个ipadx 20,给另一个ipadx 0。

    button1 = ttk.Button(inner_frame, text='this is a button')
    button2 = ttk.Button(inner_frame, text='this is a button')
    
    button1.grid(row=0, column=0, ipadx=20)
    button2.grid(row=1, column=0, ipadx=0)
    

    请注意,带有ipadx=20 的按钮更宽,多余的空间位于按钮内部,而不是按钮周围的边距。

    inner_frame 也发生了同样的事情:当它被添加到其父级时,额外的空间被添加到框架内,有效地使inner_frame 更宽。您看不到它,因为它已添加到框架内的空白空间中。

    这是重要的部分:如果您将小部件添加到 inner_frame,grid 对应用于 inner_frame 的 ipadx 值一无所知——ipadx 选项仅适用于 inner_frame及其父级,而不是其子级。在inner_frame 中添加小部件时,grid 只知道inner_frame 是 X 像素宽。

    为了说明,我们可以为按钮添加标签,类似于您的原始代码如何将按钮添加到框架中。 (注意:我们将关闭几何传播,以免按钮收缩)。

    button1.grid_propagate(False)
    label = ttk.Label(button1, text="x")
    label.grid(row=0, column=0)
    

    您应该会看到一个如下所示的窗口:

    看看按钮最左边的“x”是怎样的?那是因为它对应用于其父级的ipadx 值一无所知。它只知道按钮是 X 像素小部件,并且它应该位于按钮的左边缘。

    这就是你原来的框架和按钮发生的事情 - 按钮被添加到框架内,利用框架内的所有空间。

    【讨论】:

      【解决方案2】:

      有趣的是,我不知道这是否是一个错误,通过使包含按钮的列展开超过其最小水平尺寸来解决您的问题。

      内框第0列的最小水平尺寸是其内容的水平尺寸,也就是按钮。

      如果添加inner_frame.columnconfigure(0, weight=1),则内部填充按预期工作:

      import tkinter as tk
      from tkinter import ttk
      
      root = tk.Tk()
      
      inner_frame = ttk.LabelFrame(root_frame, text="inner_frame")
      inner_frame.grid(row=0, column=0)
      
      inner_frame.columnconfigure(0, weight=1)
      
      button = ttk.Button(inner_frame, text="this is a button")
      button.grid(row=0, column=0)
      
      # this works expected:
      inner_frame.grid_configure(ipadx=20)
      
      root.mainloop()
      

      请注意,grid_configure 默认更改第 0 列,因此我们在第 0 列的单元格中添加内部填充。

      我不知道为什么会发生这种情况。 Tcl 网格文档 (http://tcl.tk/man/tcl8.5/TkCmd/grid.htm#M13) 中没有提到它。

      有趣的是,这个链接确实提到了一些使用内部填充(在页面下方,在“内部填充”部分中)的框架大小的一些特殊情况:https://tkdocs.com/tutorial/grid.html

      差异可能很微妙。假设您有一个 20x20 的框架,并在每侧指定 5 个像素的正常(外部)填充。框架将向几何管理器请求一个 20x20 的矩形(其自然大小)。通常,这就是它会被授予的,所以它会得到一个 20x20 的矩形框,周围有一个 5 像素的边框。

      使用内部填充,几何管理器将在确定其自然大小时有效地将额外的填充添加到小部件,就好像小部件已请求 30x30 矩形一样。如果框架居中,或附加到单边或角落(使用“粘性”),您最终会得到一个 20x20 的框架,周围有额外的空间。但是,如果框架设置为拉伸(即“we”、“ns”或“nwes”的“粘性”值),它将填充额外的空间,从而产生一个 30x30 的框架,没有边框。

      但它写得很混乱,我无法完全理解它们的意思(或者即使它们在现代 Python 中是正确的)。如果有人知道上面那段是什么意思,请务必在下面评论并告诉我们!

      为整个框架添加内部填充

      您可以通过使用样式或直接将其作为参数传递给框架的构造函数来添加内部填充:

      ttk.LabelFrame(root, text="inner", padding=(20, 0))
      

      那里的填充值可以是:

      • 一个值,用于所有边的填充
      • 两个值,用于 x 和 y(按此顺序)
      • 四个值,用于从左侧开始并顺时针方向的填充。

      【讨论】:

      • 感谢您的挖掘!我也读了那一段,它让我很困惑。但是,如果inner_frame 有多个列怎么办? (另外,我简化了问题中的代码,您可能需要调整答案。)
      • grid_configure 默认更改第 0 列,因此通过执行 grid_configure(ipadx=20) 您已经配置了第 0 列的内部填充。如果要添加更多列填充,则必须这样做为每个,并调整权重,使其不为零。
      • @JoseSalvatierra:不,grid_configure 不会更改第 0 列。您一定在想grid_columnconfigure。 grid_configure 不配置行或列,它配置了从站。你写了 “所以我们在这里为第 0 列的单元格添加内部填充。” 这是不正确的。它将内部填充添加到整个小部件,而不是特定列。
      【解决方案3】:

      到目前为止,我发现在 LabelFrame 构造函数中使用 padding=... 会产生正确的结果。

      如果删除该行

      inner_frame.grid_configure(ipadx=20)
      

      并使用

      inner_frame = ttk.LabelFrame(root, text='inner_frame', padding=[20, 0])
      

      或者

      inner_frame['padding'] = [20, 0]
      

      结果如下所示:

      我不知道为什么使用ipadx 到grid_configure 不能按预期工作。

      【讨论】:

      • 内部和外部填充的工作方式不同。例如,当使用外部填充时,框架的任何背景颜色或样式都不会应用于外部填充区域。你可以把它想象成一个透明的边框。
      • @JoseSalvatierra 是的,但padding=... 似乎在内部填充,根据需要。没有?
      • 它不是内部填充,它是框架左侧的边框。在这里看起来是一样的,但是尝试在框架中添加背景颜色,您会发现不同!
      • 其实我很抱歉——您在这里使用的padding 参数与grid 无关。所以你是对的,它是内部填充,但在框架本身而不是在特定列中。
      • 是的,不知道为什么需要改变权重来应用内部填充!
      猜你喜欢
      • 2021-05-16
      • 2022-01-01
      • 1970-01-01
      • 2021-09-25
      • 1970-01-01
      • 2021-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多