6

我想用标签填充我的窗口,并且我希望它们在列大于当前窗口(或更确切地说是父框架)大小时换行。

我尝试过使用grid布局,但是我必须自己计算每行内容的大小,才能知道何时将下一个元素放在下一行中。

我问的原因是因为我想创建某种平铺文件图标。

FlowLayout或者换个方式问, TkInter有没有类似 Swing 的东西?

4

2 回答 2

8

当我想要这样的东西时,我要做的就是将文本小部件用于容器。文本小部件可以嵌入小部件,它们就像文本一样换行。只要您的小部件高度相同,效果就非常好。

例如(根据作者的要求从问题中剪切和粘贴):

textwidget = tk.Text(master)
textwidget.pack(side=tk.LEFT, fill=tk.BOTH)
for f in os.listdir('/tmp'):
    textwidget.window_create(tk.INSERT, window=tk.Label(textwidget, text=f))
于 2012-10-25T20:35:05.337 回答
1

这是一种在框架内进行流动行为的方法。

我写了一个函数来做到这一点。基本上,您将一个框架传递给函数(不是根或顶层),该函数将查看框架的所有子级,通过它们测量它们的大小并将它们放置在框架中。

这是放置程序
  • 放置第一个小部件,并将 x 移动等于其宽度的量。
  • 测量下一个小部件。
  • 如果放置下一个小部件会导致它超出框架宽度,则将其 x 值提升为 0 并将其向下提升到等于当前行中最大小部件的值(开始新行)。
  • 重置最大小部件的值,因为您要开始新行。
  • 不断重复,直到放置所有小部件。
将该过程绑定到调整框架事件的大小。
我使用了 3 个函数来完成这项工作:
  1. 运行过程的函数。
  2. 将框架的大小调整绑定到函数的函数。
  3. 取消绑定框架大小调整的功能。

以下是功能:

from tkinter import *


def _reorganizeWidgetsWithPlace(frame):
    widgetsFrame = frame
    widgetDictionary = widgetsFrame.children
    widgetKeys = []  # keys in key value pairs of the childwidgets

    for key in widgetDictionary:
        widgetKeys.append(key)

    # initialization/priming loop
    width = 0
    i = 0
    x = 0
    y = 0
    height = 0
    maxheight = 0
    # loop/algorithm for sorting
    while i < len(widgetDictionary):
        height = widgetDictionary[widgetKeys[i]].winfo_height()
        if height > maxheight:
            maxheight = height

        width = width + widgetDictionary[widgetKeys[i]].winfo_width()

        # always place first widget at 0,0
        if i == 0:
            x = 0
            y = 0
            width = widgetDictionary[widgetKeys[i]].winfo_width()

        # if after adding width, this exceeds the frame width, bump
        # widget down.  Use maximimum height so far to bump down
        # set x at 0 and start over with new row, reset maxheight
        elif width > widgetsFrame.winfo_width():
            y = y + maxheight
            x = 0
            width = widgetDictionary[widgetKeys[i]].winfo_width()
            maxheight = height

        # if after adding width, the widget row length does not exceed
        # frame with, add the widget at the start of last widget's
        # x value

        else:
            x = width-widgetDictionary[widgetKeys[i]].winfo_width()

        # place the widget at the determined x value
        widgetDictionary[widgetKeys[i]].place(x=x, y=y)
        i += 1
    widgetsFrame.update()


def organizeWidgetsWithPlace(frame):
    _reorganizeWidgetsWithPlace(frame)
    frame.bind("<Configure>", lambda event: _reorganizeWidgetsWithPlace(frame))
    _reorganizeWidgetsWithPlace(frame)


def stopOrganizingWidgetsWithPlace(frame):
    frame.unbind("<Configure>")

以下是它们的使用示例:

def main():
    root = Tk()
    root.geometry("250x250")
    myframe = Frame(root)
    # make sure frame expands to fill parent window
    myframe.pack(fill="both", expand=1)

    buttonOrganize = Button(myframe, text='start organizing',
                            command=lambda: organizeWidgetsWithPlace(myframe))
    buttonOrganize.pack()

    buttonStopOrganize = Button(myframe, text='stop organizing',
                                command=lambda: stopOrganizingWidgetsWithPlace(myframe))
    buttonStopOrganize.pack()

    ##### a bunch of widgets #####
    button = Button(myframe, text="---a random Button---")
    canvas = Canvas(myframe, width=80, height=20, bg="orange")
    checkbutton = Checkbutton(myframe, text="---checkbutton----")
    entry = Entry(myframe, text="entry")
    label = Label(myframe, text="Label", height=4, width=20)
    listbox = Listbox(myframe, height=3, width=20)
    message = Message(myframe, text="hello from Message")
    radioButton = Radiobutton(myframe, text="radio button")
    scale_widget = Scale(myframe, from_=0, to=100, orient=HORIZONTAL)
    scrollbar = Scrollbar(myframe)
    textbox = Text(myframe, width=3, height=2)
    textbox.insert(END, "Text Widget")
    spinbox = Spinbox(myframe, from_=0, to=10)

    root.mainloop()

main()
注意:

您不需要对它们进行网格化、打包或放置。只要你指定了框架,当函数被调用时,这一切都会立即完成。所以这很方便。如果您对一个小部件进行网格化,然后尝试打包另一个小部件,然后尝试放置另一个小部件,并且您会收到只能使用一个几何管理器的错误,这可能会很烦人。我相信这只会覆盖以前的选择并放置它们。我相信你可以把这个功能放进去,它会接管管理。到目前为止,这一直对我有用,但我认为你真的不应该尝试混合和匹配几何管理器。

请注意,最初按钮是打包的,但在按下按钮后,它们会被放置。

我为函数添加了“WithPlace”命名,因为我有一组类似的函数,它们与网格管理器非常相似。

于 2021-07-26T14:13:03.897 回答