Resize Tkinter Listbox widget when window resizes

2020-08-12 02:23发布

问题:

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.

回答1:

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


回答2:

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

.pack()

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)

.grid()

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

.pack() & .grid()

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