たとえば、ウィンドウをラベルで埋めたいのですが、列が現在のウィンドウ(または親フレーム)のサイズよりも大きくなったときにラベルを折り返したいと思います。
レイアウトを使用してみました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()
それらをグリッド化、パック、または配置する必要がないこと。フレームを指定する限り、関数が呼び出されたときにすべてが一度に実行されます。とても便利です。また、ウィジェットをグリッド化してから別のウィジェットをパックしてから別のウィジェットを配置しようとすると、1つのジオメトリマネージャーしか使用できないというエラーが発生するため、煩わしい場合があります。これは単に前の選択肢を上書きして配置するだけだと思います。この機能をドロップするだけで、管理が引き継がれると思います。これまでのところ、これは常にうまくいきましたが、ジオメトリマネージャーを組み合わせて使用することは絶対に避けてください。
最初はボタンがパックされていますが、ボタンを押した後、ボタンが配置されていることに注意してください。
グリッドマネージャーと非常によく似た機能を実行する同様の関数セットがあるため、関数に「WithPlace」という名前を付けました。