I'm new to Tkinter, and I've got a Listbox
widget that I'd like to automatically-resize when changing the main window's size.
Essentially I would like to have a fluid height/width Listbox. If someone can point me to some documentation or provide a bit a code / insight, I'd appreciate it.
You want to read up on the geometry managers pack and grid, which lets you place widgets in a window and specify whether they grow and shrink or not. There's a third geometry manager, place, but it's not used very often.
Here's a simple example:
import tkinter as tk
root = tk.Tk()
scrollbar = tk.Scrollbar(root, orient="vertical")
lb = tk.Listbox(root, width=50, height=20, yscrollcommand=scrollbar.set)
scrollbar.config(command=lb.yview)
scrollbar.pack(side="right", fill="y")
lb.pack(side="left",fill="both", expand=True)
for i in range(0,100):
lb.insert("end", "item #%s" % i)
root.mainloop()
If you wish to use grid
instead of pack
, remove the two lines that call pack
and replace them with these four lines:
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
scrollbar.grid(row=0, column=1, sticky="ns")
lb.grid(row=0, column=0, sticky="nsew")
Note that with grid you have to take the extra step to configure the weight
for the row and column that contains the listbox, otherwise tkinter won't allocate any extra space to the widget.
The two main ways to allow a listbox to stretch when the window is resized are using the .pack() or .grid() methods.
SPECS:
Windows 7, Python 3.8.1, tkinter version: 8.6
I found the easiest way to do this is by using the .pack()
method, and utilizing the fill=
& expand=True
options.
import tkinter as tk
root=tk.Tk() #Creates the main window
listbox=tk.Listbox(root) #Create a listbox widget
listbox.pack(padx=10,pady=10,fill=tk.BOTH,expand=True) #fill=tk.BOTH, stretch vertically and horizontally
#fill=tk.Y, stretch vertically
#fill=tk.X, stretch horizontally
If your listbox is placed in a frame, the frame will also need to use the fill=
& expand=True
options.
import tkinter as tk
root=tk.Tk()
frame1=tk.Frame(root)
frame1.pack(fill=tk.BOTH, expand=True)
listbox=tk.Listbox(frame1)
listbox.pack(padx=10,pady=10,fill=tk.BOTH,expand=True)
The alternative technique is to use the .grid()
method and utilize thesticky=
option. In addition, you will need to configure the row and column that the listbox resides in.
import tkinter as tk
root=tk.Tk() #create window
root.columnconfigure(0,weight=1) #confiugures column 0 to stretch with a scaler of 1.
root.rowconfigure(0,weight=1) #confiugures row 0 to stretch with a scaler of 1.
listbox=tk.Listbox(root)
listbox.grid(row=0,column=0,padx=5,pady=5,sticky='nsew')
The sticky
option causes the listbox to stick to the "North" (Top), "South" (Bottom), "East" (Right), and "West" (Left) sides of the cell as it is stretched.
If your listbox is placed within a frame, you will need to configure the column and row that the frame is in, along with configure the column and row that the listbox is in.
import tkinter as tk
root=tk.Tk() #create window
root.columnconfigure(0,weight=1)
root.rowconfigure(0,weight=1)
frame1=tk.Frame(root)
frame1.grid(row=0,column=0,sticky='nsew')
frame1.columnconfigure(0,weight=1)
frame1.rowconfigure(0,weight=1)
listbox=tk.Listbox(frame1)
listbox.grid(row=0,column=0,padx=5,pady=5,sticky='nsew')
Now there is one other technique, but some people frown on it. The third technique is to utilize the .pack()
method and .grid()
method in the same script. You can mix different geometry management method in the same script as long as only a one management type is used per container. You can see an example of this below.
import tkinter as tk
root=tk.Tk() #create window
frame1=tk.Frame(root) #container: root
frame1.pack(fill=tk.BOTH,expand=True)
frame1.columnconfigure(0,weight=1)
frame1.rowconfigure(0,weight=1)
frame1.rowconfigure(1,weight=1)
listbox=tk.Listbox(frame1) #container: frame1
listbox.grid(row=0,rowspan=2,column=0,padx=5,pady=5,sticky='nsew')
btn1=tk.Button(frame1,text='Demo1') #container: frame1
btn1.grid(row=0,column=1, padx=5, pady=5)
btn2=tk.Button(frame1,text='Demo2') #container: frame1
btn2.grid(row=1,column=1, padx=5, pady=5)
frame2=tk.Frame(root) #container: root
frame2.pack()
btn3=tk.Button(frame2,text='Demo3') #container: frame2
btn3.grid(row=0,column=0)
You can see above that the frames used .pack()
while the listbox and buttons used .grid()
. This was possible because the frames resided within the root container, while the listbox and buttons resided within their respective frames.
To check you tkinter version use:
import tkinter as tk
print(tk.TkVersion)
If you would like to learn about the differences between fill and expand, please see the following link. https://effbot.org/tkinterbook/pack.htm
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With