How to auto-wrap widget in tkinter?

Question:

I saw this function (layout?) in android a few years ago, but I can’t remind what is this function name…

I need an auto-replace widget.
if the new widget’ width meets the end of the window, I want to move that widget new line.

The below is my expected output.

enter image description here

enter image description here

I Think, get the width and calculate new widget position will solve it.
But, I think this is so common need. Does tkinter support it?

Asked By: Redwings

||

Answers:

Since tkinter has a canvas which gives you absolute control over positioning, you can accomplish this with just a little bit of math when adding items. You’ll have to add code to reposition the widgets when the window is resized.

A simpler approach is to use the text widget, which supports embedded images or widgets, and has support for wrapping.

Here’s a demonstration:

import tkinter as tk

root = tk.Tk()
toolbar = tk.Frame(root)
text = tk.Text(root, wrap="word", yscrollcommand=lambda *args: vsb.set(*args))
vsb = tk.Scrollbar(root, command=text.yview)

toolbar.pack(side="top", fill="x")
vsb.pack(side="right", fill="y")
text.pack(side="left",fill="both", expand=True)

COUNT = 0
def add_widget():
    global COUNT
    COUNT += 1
    widget = tk.Label(root, width=12, text=f"Widget #{COUNT}", bd=1, relief="raised",
                      bg="#5C9BD5", foreground="white", padx=4, pady=4)
    text.configure(state="normal")
    text.window_create("insert", window=widget, padx=10, pady=10)
    text.configure(state="disabled")

add_button = tk.Button(toolbar, command=add_widget, text="Add")
add_button.pack(side="left")

for i in range(9):
    add_widget()

root.mainloop()

screenshot 3x3 widgets
screenshot of expanded widget

Answered By: Bryan Oakley

Refactored code :

The code in Bryan’s answer works very well! But a little bit difficult to understand.
Thus I refactor the code

import tkinter as tk

def add_widget():
    widget = tk.Button(root, width=12, text=f"Widget", padx=4, pady=4)
    text.window_create("end", window=widget, padx=10, pady=10)

root = tk.Tk()

add_button = tk.Button(root, command=add_widget, text="Add")
add_button.pack()

text = tk.Text(root, wrap="word", yscrollcommand=lambda *args: vscroll.set(*args))
text.configure(state="disabled") 
text.pack(side="left",fill="both", expand=True)

vscroll = tk.Scrollbar(root, command=text.yview)
vscroll.pack(side="right", fill="both")

root.mainloop()
Answered By: ᄃᄃᄃ
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.