Listbox in Tk (tkinter)

The listbox (Listbox) is a Tcl/Tk widget that allows you to display a list of strings that can be selected by the user.

/images/listbox-in-tk-tkinter/tkinter-listbox.png

Listboxes do not support icons or columns. If you need a table-like widget use the ttk.Treeview class instead.

To add a listbox to a Tk window, create an instance of the tk.Listbox class.

import tkinter as tk
root = tk.Tk()
root.geometry("400x300")
root.title("Listbox in Tk")
listbox = tk.Listbox()
listbox.pack()
root.mainloop()

Managing Items

Add an item to the list via the insert() method:

import tkinter as tk
root = tk.Tk()
root.geometry("400x300")
root.title("Listbox in Tk")
listbox = tk.Listbox()
listbox.insert(0, "Python")
listbox.pack()
root.mainloop()

The first argument specifies the position where you want to put the element, which can be any numeric value, or tk.END to indicate the end of the list. Every argument passed to insert() after the position will be added as an item to the listbox:

# Add four elements to the end of the list.
listbox.insert(tk.END, "Python", "C", "C++", "Java")

If the elements to be added are already stored in a list or tuple, it is better to do:

items = (
    "Python",
    "C",
    "C++",
    "Java"
)
# Add elements stored in a list or tuple.
listbox.insert(0, *items)

It is possible to know the number of items in a list via the size() function, which returns an integer.

items = (
    "Python",
    "C",
    "C++",
    "Java"
)
listbox.insert(0, *items)
print(listbox.size())   # Prints 4

Use the get() method to retrieve an item from the list if you know its position or index.

items = (
    "Python",
    "C",
    "C++",
    "Java"
)
listbox.insert(0, *items)
print(listbox.get(2))  # Prints C++

And delete() to remove it:

# Remove the C++ element.
listbox.delete(2)

Both functions above also work with ranges. For example, the following code returns a tuple with all the elements of the list.

# Get items from position 0 to the end.
listbox_items = listbox.get(0, tk.END)
print(listbox_items)  # Prints ('Python', 'C', 'C++', 'Java')

While this one deletes every item:

# Clear the listbox.
listbox.delete(0, tk.END)

The listvariable Parameter

Another way to handle items in a listbox is via the Tcl/Tk variable system. If you associate a Tk variable while creating the listbox instance then all changes made to it are automatically reflected in the widget.

import tkinter as tk
root = tk.Tk()
root.geometry("400x300")
root.title("Listbox in Tk")
listbox = tk.Listbox()
items = tk.StringVar()
items.set(
    "Python "
    "C "
    "C++ "
    "Java "
)
listbox = tk.Listbox(listvariable=items)
listbox.pack()
root.mainloop()

This is probably a reasonable approach in Tcl, but it's not suited for Python data structures. As you can see, all items are added as a single string separated by a space. Thus, if you want to get the elements of the listbox, the variable's get() method also returns a string:

listbox_items = items.get()
print(listbox_items, type(listbox_items))

This prints:

('Python', 'C', 'C++', 'Java') <class 'str'>

If you wanted to access a single element, you would convert it to a real tuple via the eval() built-in function:

# Convert to a tuple.
t = eval(items.get())
# Access the first element.
print(t[0])

However, this is a highly unsafe method and should be used with great care. The eval() function allows you to evaluate Python code from arbitrary strings. If the string comes from the user, an attacker could inject malicious Python code into your application.

Managing Selection

By default a listbox can have only one selected item (tk.BROWSE). To change this behavior and allow multiple selections, the tk.EXTENDED value must be passed to the selectmode parameter when creating the widget.

import tkinter as tk
root = tk.Tk()
root.geometry("400x300")
root.title("Listbox in Tk")
# Allow multiple selected items at the same time.
listbox = tk.Listbox(selectmode=tk.EXTENDED)
items = (
    "Python",
    "C",
    "C++",
    "Java"
)
listbox.insert(0, *items)
listbox.pack()
root.mainloop()

The curselection() method returns a tuple with the position (or indices) of the selected elements. Typically you will want to use this method in response to some event, like a button press, for example:

import tkinter as tk
from tkinter import messagebox, ttk
def get_selection():
    # This returns a tuple containing the indices (= the position)
    # of the items selected by the user.
    indices = listbox.curselection()
    messagebox.showinfo(
        title="Selected Items",
        # Get the text of each selected item and
        # show them separated by commas.
        message=", ".join(listbox.get(i) for i in indices)
    )
root = tk.Tk()
root.geometry("400x300")
root.title("Lista en Tk")
listbox = tk.Listbox(selectmode=tk.EXTENDED)
items = (
    "Python",
    "C",
    "C++",
    "Java"
)
listbox.insert(0, *items)
listbox.pack()
get_selection_button = ttk.Button(
    text="Get selection",
    command=get_selection
)
get_selection_button.pack()
root.mainloop()
/images/listbox-in-tk-tkinter/tkinter-listbox-selected-items.png

Note that curselection() returns a tuple with the selected indices. To get the text of each item from the index use the get() method, as seen in line 13 of the previous code.

To add one or more elements to the selection use selection_set().

# Select the third element.
listbox.selection_set(2)
# Select all elements.
listbox.selection_set(0, tk.END)

And use selection_clear() in the same manner to remove the selection.

Finally, selection_includes() returns True if the item with the specified position is selected, False otherwise.

items = (
    "Python",
    "C",
    "C++",
    "Java"
)
listbox.insert(0, *items)
listbox.selection_set(2)
print(listbox.selection_includes(2))  # Prints True.

Miscellaneous

The see() method adjusts the view of the listbox to make a given element visible. For example:

import tkinter as tk
root = tk.Tk()
root.geometry("400x300")
root.title("Listbox in Tk")
listbox = tk.Listbox()
for i in range(1, 101):
    listbox.insert(tk.END, f"Item {i}")
# Scroll the listbox view to item at position 30.
listbox.see(30)
listbox.pack()
root.mainloop()

Scrollbars

The following code adds a vertical scrollbar (ttk.Scrollbar) when the number of items in the list exceeds the visible limit.

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry("400x300")
root.title("Listbox in Tk")
# Frame to contain the listbox and scrollbar.
frame = ttk.Frame()
listbox = tk.Listbox()
# Create a scrollbar with vertical orientation.
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)
# Link it to the listbox.
listbox = tk.Listbox(frame, yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
listbox.pack()
frame.pack()
# Insert 100 items.
for i in range(1, 101):
    listbox.insert(tk.END, f"Item {i}")
root.mainloop()
/images/listbox-in-tk-tkinter/tkinter-listbox-with-scrollbar.png

If the text of the elements exceeds the width of the listbox, a horizontal scrollbar can also be included:

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry("400x300")
root.title("Listbox in Tk")
frame = ttk.Frame()
listbox = tk.Listbox()
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)
hscrollbar = ttk.Scrollbar(frame, orient=tk.HORIZONTAL)
listbox = tk.Listbox(
    frame, yscrollcommand=scrollbar.set, xscrollcommand=hscrollbar.set
)
scrollbar.config(command=listbox.yview)
hscrollbar.config(command=listbox.xview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
hscrollbar.pack(side=tk.BOTTOM, fill=tk.X)
listbox.pack()
frame.pack()
for i in range(1, 101):
    listbox.insert(tk.END, f"This is the {i} element of the list")
root.mainloop()

Styles

The tk.Listbox class accepts a series of parameters to modify the style of the widget.

You might have noticed that by default the listbox contains a border. The property that controls this style is borderwidth, which specifies its size in pixels. To remove it use:

listbox = tk.Listbox(borderwidth=0)

Also, items become underlined when they are selected. To remove it, the activestyle property must be set to tk.NONE (another value can be tk.DOTBOX, to draw a dotted box).

listbox = tk.Listbox(activestyle=tk.NONE)

Tk allows setting the color of the border that is displayed around the listbox when it has focus. For example, the following code draws a red box when the widget doesn't have focus and a blue box when it does.

listbox = tk.Listbox(highlightcolor="#0000ff", highlightbackground="#ff0000")

Colors are indicated by a # followed by hexadecimal values in RGB format. You can use this color picker to build color codes.

It is also possible to customize the thickness (in pixels) via highlightthickness.

The background color and text color is generally controlled by the background or bg and foreground or fg properties, respectively.

# Black background and white text.
listbox = tk.Listbox(bg="#000", fg="#fff")
/images/listbox-in-tk-tkinter/tkinter-listbox-styled.png

Other configurable properties include selectbackground, selectforeground, and selectborderwidth, which determine the background color, text color, and border size of a selected element.

# Green background with white text for selection.
listbox = tk.Listbox(selectforeground="#ffffff",
                    selectbackground="#00aa00",
                    selectborderwidth=5)
/images/listbox-in-tk-tkinter/tkinter-listbox-selection-styled.png

And to change the font:

listbox = tk.Listbox(font=Font(family="Sans Serif", size=10))

The Font class must be imported previously via from tkinter.font import Font.

Finally, individual items can also be styled by indicating their position via the itemconfigure function.

listbox = tk.Listbox()
items = (
    "Python",
    "C",
    "C++",
    "Java"
)
listbox.insert(0, *items)
listbox.itemconfigure(0, bg="#00aa00", fg="#fff")
listbox.itemconfigure(3, bg="#ff0000", fg="#fff")
/images/listbox-in-tk-tkinter/tkinter-listbox-styled-items.png

Valid properties for individual elements are background or bg, foreground or fg, selectbackground and selectforeground.