Home > Software design >  Resize contents inside tkinter canvas
Resize contents inside tkinter canvas

Time:12-14

I am attempting to make a canvas that contains a window with labels inside that will resize when the window is resized. Here's my code.

import tkinter as tk


main_win = tk.Tk()
main_win.test_number = 0

main_canvas = tk.Canvas(master=main_win, borderwidth=2, relief='ridge', highlightthickness=0)
main_canvas.pack(side='top', fill='both', expand=True, padx=30, pady=30)
canvas_frame = tk.Frame(master=main_canvas, borderwidth=2, relief='ridge')
main_canvas.create_window((4,4), window=canvas_frame, anchor='nw')

def _on_config(widget):
    main_win.test_number  =1
    print(main_win.test_number)

    canvas_width = main_canvas.winfo_width()
    widget.config(width=canvas_width)

inner_lbl_frame_1 = tk.Frame(master=canvas_frame, borderwidth=2, relief='ridge')
inner_lbl_frame_1.pack(side='top', fill='x', expand=True)
lbl_test_1 = tk.Label(master=inner_lbl_frame_1, text="Test |")
lbl_test_1.pack(side='left', padx=5, pady=5)
lbl_verify_1 = tk.Label(master=inner_lbl_frame_1, text="To Verify |")
lbl_verify_1.pack(side='left', padx=5, pady=5)
lbl_conclusion_1 = tk.Label(master=inner_lbl_frame_1, text="If Resize Works")
lbl_conclusion_1.pack(side='left', fill='x', expand=True, padx=5, pady=5)

inner_lbl_frame_2 = tk.Frame(master=canvas_frame, borderwidth=2, relief='ridge')
inner_lbl_frame_2.pack(side='top', fill='x', expand=True)
lbl_test_2 = tk.Label(master=inner_lbl_frame_2, text="Test |")
lbl_test_2.pack(side='left', padx=5, pady=5)
lbl_verify_2 = tk.Label(master=inner_lbl_frame_2, text="To Verify |")
lbl_verify_2.pack(side='left', padx=5, pady=5)
lbl_conclusion_2 = tk.Label(master=inner_lbl_frame_2, text="If Resize Works")
lbl_conclusion_2.pack(side='left', fill='x', expand=True, padx=5, pady=5)

main_win.bind("<Configure>", lambda e: _on_config(canvas_frame))

main_win.mainloop()

When I run this, it get's stuck in an endless loop. I attempted to research this issue on my own, but, as it is a somewhat specific issue, I haven't seen any answers. Please explain why this doesn't work and how I can make it better..

To address the number of frames I'm using, it is for layout purposes. I will be adding many more label frames that contain labels in order to hold a lot of visual data, but this was the best minimum reproducible example I could write.

I'm using Python 3.9.2.

CodePudding user response:

You should not bind the event on main_win because it will inherit to its children including canvas_frame. So changing the width of canvas_frame inside _on_change() will trigger the event and call the function again, and this causes the recursive loop.

You should bind on main_canvas instead and use main_canvas.itemconfigure() to change the width of the frame:

...
# save the item ID of the frame
frame_id = main_canvas.create_window((4,4), window=canvas_frame, anchor='nw')

def _on_config(event, widget_id):
    main_win.test_number  = 1
    print(main_win.test_number)
    # use itemconfigure(...) on the passed widget_id
    event.widget.itemconfigure(widget_id, width=event.width-8)

...

# bind on main_canvas instead of main_win
main_canvas.bind('<Configure>', lambda e: _on_config(e, frame_id))
...
  • Related