我想用标签填充我的窗口,并且我希望它们在列大于当前窗口(或更确切地说是父框架)大小时换行。
我尝试过使用grid
布局,但是我必须自己计算每行内容的大小,才能知道何时将下一个元素放在下一行中。
我问的原因是因为我想创建某种平铺文件图标。
FlowLayout
或者换个方式问, TkInter有没有类似 Swing 的东西?
我想用标签填充我的窗口,并且我希望它们在列大于当前窗口(或更确切地说是父框架)大小时换行。
我尝试过使用grid
布局,但是我必须自己计算每行内容的大小,才能知道何时将下一个元素放在下一行中。
我问的原因是因为我想创建某种平铺文件图标。
FlowLayout
或者换个方式问, TkInter有没有类似 Swing 的东西?
当我想要这样的东西时,我要做的就是将文本小部件用于容器。文本小部件可以嵌入小部件,它们就像文本一样换行。只要您的小部件高度相同,效果就非常好。
例如(根据作者的要求从问题中剪切和粘贴):
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))
我写了一个函数来做到这一点。基本上,您将一个框架传递给函数(不是根或顶层),该函数将查看框架的所有子级,通过它们测量它们的大小并将它们放置在框架中。
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”命名,因为我有一组类似的函数,它们与网格管理器非常相似。