【问题标题】:Why is TKinter OptionMenu changing the size of it's parent?为什么 TKinter OptionMenu 会改变其父级的大小?
【发布时间】:2016-06-16 23:30:26
【问题描述】:

我有这个 GUI 程序,其中一个框架中有一个 OptionMenu。每当我在 OptionMenu 中选择某些内容时,它都会调整父框架的大小,即使它有足够的空间容纳当前面板。这很难用语言来描述,所以这里是我的意思的图像:

可以看到,随着 OptionMenu 尺寸的增加,紫色、蓝色和红色的边框都扩大了。

窗口分为左右两个Frame,采用Grid Layout,权重分别为3和2。两个框架里面是每个彩色面板的Pack布局,设置为填充X。在Purple里面,我设置了这个optionMenu,并把它打包到面板的左边。

当它改变其内容时,它会调整整个右框架的大小,忽略网格权重并破坏 GUI 的平衡。如果我为 OptionMenu 设置了固定宽度,它不会调整大小,但仍会使框架与 GridLayout 不对齐。我怎样才能让框架不根据这个元素的宽度调整大小,而只需将元素放在框架内,即使在最宽的地方,它也有足够的空间来处理它?

这是我正在使用的 GUI 代码的简化版本,完整的代码有点太长了,因为每个面板都被分解成类以供将来使用:

root = Tk()
root.geometry('640x480')

#Begin defining left frame areas
leftFrame = Frame(root)

grayPanel = Frame(leftFrame,bg="gray")
whitePanel = Frame(leftFrame,bg="white", height=50)
grayPanel.pack(expand=True,fill=BOTH)
whitePanel.pack(fill=X)

#Begin defining right frame areas
rightFrame = Frame(root)

purplePanel = Frame(rightFrame,bg="purple", height=50)
bluePanel = Frame(rightFrame,bg="blue")
redPanel = Frame(rightFrame,bg="red", height=100)

purplePanel.pack(fill=X)
bluePanel.pack(expand=True,fill=BOTH)
redPanel.pack(fill=X)

#create the options dropdown for purple
currentOption = StringVar(purplePanel)
currentOption.set("None")
optList = ["None","Some incredibly long string that breaks everything"]
options = OptionMenu(purplePanel,currentOption,*optList)
options.pack(side=LEFT)


leftFrame.grid(row=0,column=0,sticky=N+S+E+W)
rightFrame.grid(row=0,column=1,sticky=N+S+E+W)

root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=3)
root.grid_columnconfigure(1, weight=2)

root.mainloop()

【问题讨论】:

    标签: python tkinter grid-layout optionmenu


    【解决方案1】:

    问题的根源在于您没有为任何小部件指定大小,并且所有框架都是空的。以下描述可能听起来令人困惑,但它实际上非常合乎逻辑、确定性并且与记录的行为一致。

    小部件和列的自然大小

    因为没有一个框架有明确的宽度,所以它们默认宽度为 0(零)。选项菜单的行为是调整其大小以使其足够大以显示该值(我认为在 Mac 上除外)。它是唯一具有非零请求(或“自然”)大小的小部件。

    网格负责左右两边。左侧尺寸为零宽度,右侧是选项菜单的宽度。为了便于讨论,假设它是 140 像素宽,只是为了方便计算;实际大小可能更大或更小,具体取决于您的字体,我们忽略了边框以保持数学简单。因此,grid 认为左边想要为零,而右边想要 140。这是它试图让一切都合适时开始的唯一信息。

    处理多余的空间

    您强制窗口为 640 像素宽,但它的子窗口只需要 140 像素,因此它有 500 额外像素。左侧使用 3 列权重,右侧使用 2 列权重,因此,每增加 5 个像素的额外空间,左侧有 3 个,右侧有 2 个。这意味着左列将获得 300 像素的额外空间,右列将获得 200 像素的额外空间。这使得左列 300 像素 (0+300) 和右列 340 (140+200)。这就是为什么它们在启动时看起来大致相同的原因。

    当你改变选项菜单的大小时会发生什么

    现在,您更改选项菜单的值,使其增长。假设选项菜单的新宽度是 440 像素。左侧仍然希望为零,但现在右侧希望为 440。这意味着只有 200 像素的额外空间:左侧为 120,右侧为 80。请记住,左列的自然大小为零,因此零加 120 意味着左列将是 120 像素宽。在右侧,自然大小为 440。440 加上额外的 80 意味着右侧现在将是 520 像素宽。

    这就是为什么当有长的选项菜单时,左侧收缩和右侧有额外的空间。您要求左边为零,因此只有在布置了所有其他具有实际大小的小部件后才能使用额外的空间。右侧有一个非零的自然大小,但网格算法有剩余空间,它必须分配给右侧。

    如何获得统一的列宽

    您没有问,但我假设后续问题将是“如何使两列大小相同?”答案是使用带有网格的uniform 选项。告诉 grid 你希望两列的大小一致,如下所示:

    root.grid_columnconfigure(0, weight=3, uniform="column")
    root.grid_columnconfigure(1, weight=2, uniform="column")
    

    uniform 将任何字符串作为参数。具有相同值的所有列(或行)都被视为“统一组”。

    请注意,对于uniform,网格仍然尊重权重。只是uniform 保证列严格遵循列权重。在您的情况下,这意味着您的左右宽度之间的比例为 3:2

    关于网格和包算法的规范信息

    Tkinter 是使用 tk 工具包的 tcl 解释器的包装器。虽然语法与 python 不同,但很容易将 tcl 文档翻译成 python。以下是关于gridpack 工作原理的描述链接:

    【讨论】:

    • 精彩的文章!谢谢你。我现在对这些布局的工作原理有了更好的了解,统一选项解决了我的问题。
    猜你喜欢
    • 1970-01-01
    • 2020-05-24
    • 2021-12-20
    • 1970-01-01
    • 2015-08-31
    • 2019-08-02
    • 2016-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多