【问题标题】:tkinter sticky not working for some framestkinter 粘性不适用于某些帧
【发布时间】:2015-10-28 22:01:30
【问题描述】:

我正在使用 tkinter 编写纸牌游戏,但我在网格布局管理器的“粘性”配置方面遇到了问题。我想帮助修复我的代码以使框架显示在所需的位置。在我的代码和下面的插图中,有一个框架 (b2) 包含另外两个(一个绿色,b2a;一个红色;b2b)框架。我想在父框架(框架 b)的底部显示框架 b2。对于框架 b2 和子框架 b2a 和 b2b,我尝试了 N+S+E+W 的各种组合作为“粘性”的参数。但是,我无法让帧 b2(更重要的是 b2a 和 b2b)出现在所需的位置(下面的底部图片正确放置是在 Illustrator 中制作的)。

特别是,第 27、36 和 37 行中的粘性参数似乎对 b2、b2a 和 b2b 框架在 b 框架内的放置没有影响。

from tkinter import *
from PIL import Image, ImageTk

def main(root):
    cons = Frame(root)
    cons.grid()

    frameDict = setup_frames(cons)
    populate_frames(frameDict)

def setup_frames(cons):
    frame = {}
    # Parental Frames
    frame['a'] = Frame(cons, borderwidth=2, relief='groove')
    frame['b'] = Frame(cons, borderwidth=2, relief='groove')
    frame['c'] = Frame(cons, borderwidth=2, relief='groove')

    frame['a'].grid(row=0, column=0, sticky=N+S+E+W)
    frame['b'].grid(row=0, column=1, sticky=N+S+E+W)
    frame['c'].grid(row=1, column=0, columnspan=2)

    # Progeny 0 Frames:
    frame['b1'] = Frame(frame['b'], borderwidth=2, relief='groove')
    frame['b2'] = Frame(frame['b'], borderwidth=2, relief='groove')

    frame['b1'].grid(row=0, column=0, sticky=N+S+E+W)
    frame['b2'].grid(row=1, column=0, sticky=N+S+E+W)

    # Progeny 1 Frames:

    frame['b2a'] = Frame(frame['b2'], borderwidth=2, relief='groove',
                         background='green')
    frame['b2b'] = Frame(frame['b2'], borderwidth=2, relief='groove',
                         background='red')

    frame['b2a'].grid(row=0, column=0, sticky=S)
    frame['b2b'].grid(row=0, column=1, sticky=SW)

    return frame

def populate_frames(fr):

    # Populating 'a' frame
    aLab = Label(fr['a'], image=img[0])
    aLab.grid()

    # Populating b2a & b2b frames
    bLab = Label(fr['b2a'], image=img[1])
    bLab.grid(row=0, column=0)

    bLab = Label(fr['b2b'], image=img[2])
    bLab.grid(row=0, column=1)

    # Populating c1 frame
    cLab = Label(fr['c'], image=img[3])
    cLab.grid()

if __name__ == '__main__':
    root = Tk()
    img = []
    w = [40,  160, 80, 480]
    h = [180, 60,  60, 60]
    for i in range(4):
        a = Image.new('RGBA', (w[i], h[i]))
        b = ImageTk.PhotoImage(a)
        img.append(b)
    main(root)

下面的图片说明了违规框架(绿色和红色)的显示位置(顶部)以及我希望它们显示的位置(底部)。

有人可以帮我在正确的位置显示框架 b2(最终是 b2a 和 b2b)吗(编辑:在框架 b 的底部,从框架 a 的右侧跨越到框架 c 的右侧)?

更新: 正如 Bryan 所建议的,我已经使用网格权重解决了这两个问题(框架 b2 的垂直放置和水平对齐)。垂直放置问题的解决方案很简单,但我没有预料到水平对齐问题的解决方案。

我通过将 weight=1 赋予帧 b 中的第 0 行来解决垂直放置问题(导致下图的上面板)。

我通过将 weight=1 分配给帧 b 中的第 0 列解决了水平对齐问题(其中帧 b1 和 b2 未拉伸以填充帧 b)。下图中的帧轮廓显示,帧 b 已经从帧 a 的右侧拉伸到帧 c 的右侧。对我来说很奇怪,需要给框架中唯一的列赋予权重以允许子框架水平填充。无论如何,我在下面粘贴了我的工作代码。第 40 行和第 41 行解决了我遇到的问题。

from tkinter import *
from PIL import Image, ImageTk

def main(root):
    cons = Frame(root)
    cons.grid()

    frameDict = setup_frames(cons)
    populate_frames(frameDict)

def setup_frames(cons):
    frame = {}
    # Parental Frames
    frame['a'] = Frame(cons, borderwidth=2, relief='groove')
    frame['b'] = Frame(cons, borderwidth=2, relief='groove')
    frame['c'] = Frame(cons, borderwidth=2, relief='groove')

    frame['a'].grid(row=0, column=0, sticky=N+S+E+W)
    frame['b'].grid(row=0, column=1, sticky=N+S+E+W)
    frame['c'].grid(row=1, column=0, columnspan=2)

    # Progeny 0 Frames:
    frame['b1'] = Frame(frame['b'], borderwidth=2, relief='groove')
    frame['b2'] = Frame(frame['b'], borderwidth=2, relief='groove')

    frame['b1'].grid(row=0, column=0, sticky=N+S+E+W)
    frame['b2'].grid(row=1, column=0, sticky=N+S+E+W)

    # Progeny 1 Frames:

    frame['b2a'] = Frame(frame['b2'], borderwidth=2, relief='groove',
                         background='green')
    frame['b2b'] = Frame(frame['b2'], borderwidth=2, relief='groove',
                         background='red')

    frame['b2a'].grid(row=0, column=0, sticky=S)
    frame['b2b'].grid(row=0, column=1, sticky=SW)

    # Weighting
    frame['b'].grid_rowconfigure(0, weight=1)
    frame['b'].grid_columnconfigure(0, weight=1)

    return frame

def populate_frames(fr):

    # Populating 'a' frame
    aLab = Label(fr['a'], image=img[0])
    aLab.grid()

    # Populating b2a & b2b frames
    bLab = Label(fr['b2a'], image=img[1])
    bLab.grid(row=0, column=0)

    bLab = Label(fr['b2b'], image=img[2])
    bLab.grid(row=0, column=1)

    # Populating c1 frame
    cLab = Label(fr['c'], image=img[3])
    cLab.grid()

if __name__ == '__main__':
    root = Tk()
    img = []
    w = [40,  160, 80, 480]
    h = [180, 60,  60, 60]
    for i in range(4):
        a = Image.new('RGBA', (w[i], h[i]))
        b = ImageTk.PhotoImage(a)
        img.append(b)
    main(root)

根据 Bryan 的建议,为每个容器中的至少一列和一行分配权重似乎是一个很好的经验法则。

这是我修复水平对齐问题之前和之后:

使用 Python 3.4,优胜美地

【问题讨论】:

标签: python tkinter sticky


【解决方案1】:

你必须给一些行和列一个权重,所以 tkinter 知道如何分配额外的空间。

根据经验,使用grid 时,每个使用网格的容器都应至少赋予一行和一列的权重。

我要做的就是重新开始。有条不紊。在解决其他问题之前,先让主要的三个方面发挥作用。使这个问题难以解决的原因是没有什么行为正确,所以你试图一次调整很多事情。一次专注于一个领域,让它发挥作用,然后继续前进。

鉴于您的图表,pack 似乎比为根窗口的子级使用网格更简单的解决方案 在使用网格的其他框架内的框架内使用网格可能会令人困惑。

看起来 C 框架是某种从底部延伸的状态栏,所以先打包它。在此之上,您有两个区域 - 框架 a 位于左侧,看起来是固定宽度,框架 c 位于右侧并占用所有额外空间。使用 pack,它看起来像这样:

frame['c'].pack(side="bottom", fill="x")
frame['a'].pack(side="left", fill="y")
frame['b'].pack(side="right", fill="both", expand=True)

当然,您可以使用网格获得完全相同的外观,但需要多几行代码,因为您必须为第 1 列和第 1 行赋予权重。

这应该可以让三个主要领域正常工作。现在你只需要担心帧 B 的内容。

您的图表显示您希望 b2a 和 b2b 位于框架 b 的底部,并在其上方有更多小部件。那是对的吗?如果是这种情况,您需要在其上方至少留出一排以填充额外的空间。

具有正权重的空白行将强制所有小部件移向该区域的底部。它们将仅占用垂直所需的空间,而具有非零权重的空行将占用所有额外空间。

然后您只需要担心水平放置。目前尚不清楚您的期望是什么,但解决方案再次围绕赋予列权重。如果您希望 b2a 和 b2b 均等扩展,请为两列赋予相同的权重。如果您希望 b2a 完成所有扩展,请仅给第 0 列赋予权重。

【讨论】:

  • 谢谢布莱恩。我想这应该被标记为重复问题,因为它似乎与您回答的previous one 具有相同的答案。不过还是有一点问题——我添加了frame['b'].grid_rowconfigure(0, weight=1),这会将b2 移到帧b 的底部。但是添加frame['b2'].grid_columnconfigure(0, weight=1) 仍然不允许框架 b2 扩展到框架 b 的右侧。
  • @mRotten:我已经用一些示例和其他建议更新了我的答案。
  • 使用工作代码更新问题,说明工作代码中解决的水平对齐问题。感谢 Bryan 为我指明了正确的方向。正如他还提到的,pack() 可能更适合此应用程序,但我认为值得展示的是,即使容器只有一列,不赋予该列权重也会导致来自 grid() 的意外行为。
猜你喜欢
  • 2017-09-10
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-23
  • 2014-12-17
  • 2013-06-26
相关资源
最近更新 更多