Search code examples
pythontkinterttkwidgets

How can i set a safety for ttk panedwindow resizing that all content from the panes is always visible?


I have a PanedWindow from ttk (using the ttk variant for the weights to only resize the top window using the sash, without the weight option the bottom gets resized, but i want the bottom to stay the same size), and i would like to stop the user from moving the sash down enough to move the bottom pane "outside of the window" (streamable video to show what i mean with that)
https://streamable.com/jsu50e
i would like the bottom pane to always stay on screen no matter what and the sash to stop going down if the limit is reached, minsize is not available in the ttk panedwindow from what i can tell, and the weight from the ttk variant was the easiest way for me to achieve the bottom pane not resizing when the window itself gets resized. if there is a way to get the bottom pane to stay the same size when resizing the outer window with tk.panedwindow minsize would be an option as long as i can get the height of the text size and use that to set the minsize to the size of the content of the bottom pane, as the default/min size of it currently is set using text units.

my current code:

import tkinter as tk
import tkinter.ttk as ttk

window = tk.Tk()
w_main = ttk.PanedWindow(master=window, orient=tk.VERTICAL)

frm_img = ttk.Frame(master=w_main, relief=tk.GROOVE, borderwidth=5)
lbl_img = ttk.Label(master=frm_img)
lbl_img.pack(fill=tk.BOTH, expand=True)

frm_cl = ttk.Frame(master=w_main, relief=tk.GROOVE, borderwidth=5)
frm_cl_history = ttk.Frame(master=frm_cl)
txt_cl_history = tk.Text(master=frm_cl_history, width=120, height=20)
txt_cl_history.pack(fill=tk.BOTH, expand=True)
frm_cl_entry = ttk.Frame(master=frm_cl, relief=tk.GROOVE, borderwidth=3)
ent_cl_entry = ttk.Entry(master=frm_cl_entry, width=110)
btn_cl_entry = ttk.Button(master=frm_cl_entry, width=10, text="Enter")
ent_cl_entry.pack(fill=tk.X, side=tk.LEFT, expand=True)
btn_cl_entry.pack()
frm_cl_history.pack(fill=tk.BOTH, expand=True)
frm_cl_entry.pack(fill=tk.X)

w_main.add(frm_img, weight=1)
w_main.add(frm_cl, weight=0)
w_main.pack(fill=tk.BOTH, expand=True)

window.mainloop()

Solution

  • Use tk.PaneWindow instead of ttk.PaneWindow because the former supports minsize option on the panes:

    import tkinter as tk
    import tkinter.ttk as ttk
    
    window = tk.Tk()
    # use tk.PaneWindow instead
    w_main = tk.PanedWindow(master=window, orient=tk.VERTICAL)
    
    frm_img = ttk.Frame(master=w_main, relief=tk.GROOVE, borderwidth=5)
    lbl_img = ttk.Label(master=frm_img)
    lbl_img.pack(fill=tk.BOTH, expand=True)
    
    frm_cl = ttk.Frame(master=w_main, relief=tk.GROOVE, borderwidth=5)
    frm_cl_history = ttk.Frame(master=frm_cl)
    txt_cl_history = tk.Text(master=frm_cl_history, width=120, height=20)
    txt_cl_history.pack(fill=tk.BOTH, expand=True)
    frm_cl_entry = ttk.Frame(master=frm_cl, relief=tk.GROOVE, borderwidth=3)
    ent_cl_entry = ttk.Entry(master=frm_cl_entry, width=110)
    btn_cl_entry = ttk.Button(master=frm_cl_entry, width=10, text="Enter")
    ent_cl_entry.pack(fill=tk.X, side=tk.LEFT, expand=True)
    btn_cl_entry.pack()
    frm_cl_history.pack(fill=tk.BOTH, expand=True)
    frm_cl_entry.pack(fill=tk.X)
    
    w_main.add(frm_img, stretch="always") # this pane always stretch
    w_main.add(frm_cl, stretch="never")   # this pane never stretch
    w_main.pack(fill=tk.BOTH, expand=True)
    
    # set the minsize of the bottom pane
    frm_cl.update()
    w_main.paneconfigure(frm_cl, minsize=frm_cl.winfo_height())
    
    window.mainloop()