Listbox¶
A listbox displays a list of single-line text items, and allows users to browse through the list, and selecting one or more items.
Create a listbox the old way¶
The old way of creating a listbox, was to create an empty listbox widget and then to insert item by item into the listbox.
The listbox methods insert
and delete
allow
to add or remove items a specific position.
The label tk.END
is used to add items to the end of the listbox.
Here three items are added at the top and one item is removed:
lb.insert(0, 'item0', 'item1', 'item2')
lb.delete(1)
To insert multiple items of a list one can iterate through the list:
for item in items:
lb.insert(tk.END, item)
or hand multiple items directly to the insert
method:
lb.insert(tk.END, *items)
# Create a listbox the old way, with the insert/delete method
import tkinter as tk
root = tk.Tk()
lb = tk.Listbox(root)
lb.grid()
lb.insert(0, 'item0', 'item1', 'item2')
lb.delete(1)
items = dir(tk)
for item in items:
lb.insert(tk.END, item)
lb.insert(tk.END, *items)
root.mainloop()
Create a listbox the new way¶
The new and much simpler way of handling the listbox content is to use the listvariable argument which must be set to a StringVar object. The program below displays the attributes of the Tk module as a list:
items = dir(tk)
var = tk.StringVar()
var.set(items)
At creation the listbox sets its listvariable to this list:
tk.Listbox(root, listvariable=var).grid()
# Display a simple listbox
import tkinter as tk
root = tk.Tk()
items = dir(tk)
var = tk.StringVar()
var.set(items)
tk.Listbox(root, listvariable=var).grid()
root.mainloop()
Single and extended selection mode¶
The selectmode
argument let’s the listbox be configured for
- single item selection (browse)
- multiple item selection (extended)
# Show browse/extended selectmode
import tkinter as tk
root = tk.Tk()
var = tk.StringVar(value=dir(tk))
tk.Listbox(root, listvariable=var, selectmode='browse').pack(side='left')
tk.Listbox(root, listvariable=var, selectmode='extended').pack(side='left')
root.mainloop()
root.mainloop()
ListboxSelect callback function¶
When the user selects an item, either with a mouse click or with the arrow keys, a virtual <ListboxSelect> event is generated. You can bind to it to a callback function:
lb.bind('<<ListboxSelect>>', cb)
The callback function prints the event descriptor and the current selection as an index list to a label:
def cb(event):
label['text'] = str(event) + '\n' + str(lb.curselection())
# <ListboxSelect> callback function and current selection
import tkinter as tk
def cb(event):
label['text'] = str(event) + '\n' + str(lb.curselection())
root = tk.Tk()
var = tk.StringVar(value=dir(tk))
label = tk.Label(root)
label.grid()
lb = tk.Listbox(root, listvariable=var, selectmode='extended')
lb.grid()
lb.bind('<<ListboxSelect>>', cb)
root.mainloop()
Edit a listbox item¶
In the following example we display the selected listbox item in an entry field. The entry field can be edited and hitting the return key writes the new item value to the listbox. The screen capture below shows how ANCHOR had been changed to ANCHOR_function.
# Edit listbox item with an entry widget
import tkinter as tk
def select(event):
i = lb.curselection()[0]
item.set(items[i])
def update(event):
i = lb.curselection()[0]
items[i] = item.get()
var.set(items)
root = tk.Tk()
items = dir(tk)
var = tk.StringVar(value=items)
lb = tk.Listbox(root, listvariable=var)
lb.grid()
lb.bind('<<ListboxSelect>>', select)
item = tk.StringVar()
entry = tk.Entry(root, textvariable=item, width=20)
entry.grid()
entry.bind('<Return>', update)
root.mainloop()
Listbox with search¶
Regular expression¶
"""Regular expression demo."""
from tkinter import *
from tklib import *
import re
class Browser(Listbox):
def cb(self, event):
pass
class Demo(App):
def __init__(self):
super().__init__()
Label('Regular expressions', font='Arial 18')
Label('Enter a Perl-style regular expression')
App.re = Entry('regex')
App.re.bind('<Key>', self.recompile)
App.status = Label('Status')
Checkbutton('IGNORECASE;MULITILINE;DOTALL;VERBOSE')
Label('Enter a string to search')
Radiobutton('Highlight first;Highligth all')
App.str = Text(height=10)
App.str.bind('<Key>', self.reevaluate)
App.str.tag_configure("hit", background="yellow")
Label('Groups')
App.groups = Listbox()
btags = App.re.bindtags()
App.re.bindtags(btags[1:] + btags[:1])
btags = App.str.bindtags()
App.str.bindtags(btags[1:] + btags[:1])
self.compiled = None
def recompile(self, event=None):
print('recompile')
try:
self.compiled = re.compile(App.re.get())
except re.error as msg:
self.compiled = None
App.status.config(
text="re.error: %s" % str(msg),
background="red")
self.reevaluate()
def reevaluate(self, event=None):
print('reevaluate')
try:
self.str.tag_remove("hit", "1.0", END)
except TclError:
pass
try:
self.str.tag_remove("hit0", "1.0", END)
except TclError:
pass
self.groups.delete(0, END)
if not self.compiled:
return
self.str.tag_configure("hit", background="yellow")
self.str.tag_configure("hit0", background="orange")
text = self.str.get("1.0", END)
last = 0
nmatches = 0
while last <= len(text):
m = self.compiled.search(text, last)
if m is None:
break
first, last = m.span()
if last == first:
last = first+1
tag = "hit0"
else:
tag = "hit"
pfirst = "1.0 + %d chars" % first
plast = "1.0 + %d chars" % last
self.str.tag_add(tag, pfirst, plast)
if nmatches == 0:
self.str.yview_pickplace(pfirst)
groups = list(m.groups())
groups.insert(0, m.group())
for i in range(len(groups)):
g = "%2d: %r" % (i, groups[i])
App.groups.insert(END, g)
nmatches = nmatches + 1
if self.showvar.get() == "first":
break
if nmatches == 0:
self.status.config(text="(no match)",
background="yellow")
else:
self.status.config(text="")
Demo().run()