Search code examples
pythonpython-3.xtkinter

tkinter - how to resize frame


I want to create simple gui in tkinter that consist of notebook frame and several frames inside of each tabs. Let's say I want 2 labeled frames inside each of notebook's tabs spanning 100% of window width and 50% of window height.

Screen layout

I will have more frames/elements inside that I want to take x% of the window widht/height.

I read that tkinter gui should resize automatically when window is resized, but I cannot get it to work.

  1. How do I set frames to take 100% of window width and (for example) 50% of window height?
  2. How do I center the frame so it is not stick to left-upper corner?

I cannot figure out how to do it with grid layout manager and documentation says it should be used over pack.

Example of my code:

import tkinter as tk
from tkinter import ttk, Tk

root = Tk()
root.geometry('1200x800')
root.title("Test")

tab_frame = ttk.Notebook(root)
tab_frame.grid()

####### change Notebook size in case main window changes
def conf(event):
    tab_frame.config(height=root.winfo_height(), width=root.winfo_width())
    # without this you cannot resize frames of the notebook by grid(sticky) or width/height !
    return
    
root.bind("<Configure>",conf)
#######

s1 = ttk.Style()
s1.configure('test_red.TFrame', background='red')
s2 = ttk.Style()
s2.configure('test_green.TFrame', background='green')
s3 = ttk.Style()
s3.configure('test_blue.TFrame', background='blue')


tab1 = ttk.Frame(tab_frame, height=100, width=100, style='test_red.TFrame')
tab1.grid()
tab2 = ttk.Frame(tab_frame, height=100, width=100, style='test_blue.TFrame')
tab2.grid()

tab_frame.add(tab1, text='Tab1')
tab_frame.add(tab2, text='Tab2')

### frames in tab
label_frame1 = ttk.Labelframe(tab1, text='Label1', width=100, height=100, style='test_green.TFrame')
label_frame1.grid()
#label_frame.grid(sticky='e') # sticky does not work in any combination

label_frame2 = ttk.Labelframe(tab1, text='Label2', width=100, height=100, style='test_blue.TFrame')
label_frame2.grid()

root.mainloop()

Solution

  • First you can use tab_frame.pack(fill="both", expand=1) instead of .grid() and then you don't need to bind <Configure> event to resize tab_frame.

    Second you can use rowconfigure() and columnconfigure() to make the two LabelFrames to fill horizontally and vertically.

    import tkinter as tk
    from tkinter import ttk
    
    root = tk.Tk()
    root.geometry('1200x800')
    root.title("Test")
    
    tab_frame = ttk.Notebook(root)
    tab_frame.pack(fill="both", expand=1) # used pack() instead of grid()
    
    s = ttk.Style()
    s.configure('test_red.TFrame', background='red')
    s.configure('test_green.TFrame', background='green')
    s.configure('test_blue.TFrame', background='blue')
    
    tab1 = ttk.Frame(tab_frame, style='test_red.TFrame')
    tab2 = ttk.Frame(tab_frame, style='test_blue.TFrame')
    
    tab_frame.add(tab1, text='Tab1')
    tab_frame.add(tab2, text='Tab2')
    
    # make two LabelFrames to fill horizontally
    tab1.columnconfigure(0, weight=1)
    # make two LabelFrames to evenly fill vertically
    tab1.rowconfigure((0,1), weight=1)
    
    ### frames in tab
    label_frame1 = ttk.Labelframe(tab1, text='Label1', style='test_green.TFrame')
    label_frame1.grid(sticky="nsew")
    
    label_frame2 = ttk.Labelframe(tab1, text='Label2', style='test_blue.TFrame')
    label_frame2.grid(sticky="nsew")
    
    root.mainloop()
    

    You can use place() on the two LabelFrames to achieve same goal:

    import tkinter as tk
    from tkinter import ttk
    
    root = tk.Tk()
    root.geometry('1200x800')
    root.title("Test")
    
    tab_frame = ttk.Notebook(root)
    tab_frame.pack(fill="both", expand=1) # used pack() instead of grid()
    
    s = ttk.Style()
    s.configure('test_red.TFrame', background='red')
    s.configure('test_green.TFrame', background='green')
    s.configure('test_blue.TFrame', background='blue')
    
    tab1 = ttk.Frame(tab_frame, style='test_red.TFrame')
    tab2 = ttk.Frame(tab_frame, style='test_blue.TFrame')
    
    tab_frame.add(tab1, text='Tab1')
    tab_frame.add(tab2, text='Tab2')
    
    ### frames in tab
    label_frame1 = ttk.Labelframe(tab1, text='Label1', style='test_green.TFrame')
    label_frame1.place(x=0, y=0, relwidth=1, relheight=0.5)
    
    label_frame2 = ttk.Labelframe(tab1, text='Label2', style='test_blue.TFrame')
    label_frame2.place(x=0, rely=0.5, relwidth=1, relheight=0.5)
    
    root.mainloop()