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.
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.
- How do I set frames to take 100% of window width and (for example) 50% of window height?
- 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()
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!
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()
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 LabelFrame
s 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()
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.
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.
- How do I set frames to take 100% of window width and (for example) 50% of window height?
- 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()
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!
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()
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 LabelFrame
s 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()