tkinter – how to resize frame

Question:

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()
Asked By: Roman

||

Answers:

Just following @TheLizzard’s comment and writing answer.

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()

def conf(event):
    tab_frame.config(height=root.winfo_height(), width=root.winfo_width())
    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.pack(fill="x")
tab2 = ttk.Frame(tab_frame, height=100, width=100, style='test_blue.TFrame')
tab2.pack(fill="both")

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

label_frame1 = ttk.Labelframe(tab1, text='Label1', width=100, height=100, style='test_green.TFrame')
label_frame1.pack(fill="x")

label_frame2 = ttk.Labelframe(tab1, text='Label2', width=100, height=100, style='test_blue.TFrame')
label_frame2.pack(fill="both", expand=True)

root.mainloop()

If this solve your problem then mark this as answer!

Answered By: imxitiz

Here is a simplified resizable Notebook with two labelframes each containing a button.

The problem you are having is due to the grid manager default not being resizable, unlike other managers.

The solution is to use function flexx.

flexx is a necessary function that makes grid objects flexible.

flexx is always applied to containers like labelframes, frames and the root or master widget

grid is a convenience function

You should be able to populate each notebook tab with any number of widgets.

The thing to remember is containers like labelframe must contain some widget to exist.

Applying flexx to the root is essential in order to make Tk or ‘Toplevel window flexible.

import tkinter as tk
from tkinter import ttk, Tk

def flexx( o, r = 0, c = 0, rw = 1, cw = 1 ):
    '''flexx will control grid manager static|dymanic growth'''
    if r != None:
        o.rowconfigure( r, weight = rw )
    if c != None:
        o.columnconfigure( c, weight = cw )

def grid( r = 0, c = 0, s = 'nsew', rs = 1, cs = 1 ) ->'Grid manager settings':
    '''grid( r = 0, c = 0, s = nsew, rs = 1, cs = 1 )'''
    return dict( row=r, column=c, rowspan=rs, columnspan=cs, sticky=s )


root = Tk()
root.geometry('568x427')
root.title("Test")
flexx( root ) # essential for other objects to resize

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

def closer( ev = None ):
    root.destroy( )

root.bind( '<Escape>', closer )

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 objects
label_frame1 = ttk.Labelframe( tab_frame, labelanchor= 'n', text='Label1', style='test_green.TFrame')
label_frame1.grid( grid( ) )
flexx( label_frame1 )
tk.Button( label_frame1, text = 'button_1' ).grid( grid() )
tab_frame.add(label_frame1, text='Tab1')
tk.Button( label_frame1, text = 'button_2' ).grid( grid(r=1) )
flexx( label_frame1, r=1 )

# Tab2 objects
label_frame2 = ttk.Labelframe( tab_frame, labelanchor= 'n', text='Label2', style='test_blue.TFrame')
label_frame2.grid( grid( ) )
flexx( label_frame2 )
tk.Button( label_frame2, text = 'button_3' ).grid( grid() )
tab_frame.add(label_frame2, text='Tab1')
tk.Button( label_frame2, text = 'button_4' ).grid( grid(r=1) )
flexx( label_frame2, r=1 )
tab_frame.add(label_frame2, text='Tab2')

root.mainloop()
Answered By: Derek

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()
Answered By: acw1668
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.