61

There are a number of ways of getting callbacks when Text or Entry widgets are changed in Tkinter, but I haven't found one for Listbox's (it doesn't help that much of the event documentation I can find is old or incomplete). Is there some way of generating an event for this?

bfops
  • 5,348
  • 5
  • 36
  • 48
  • 4
    All virtual events are listed at: [The Tcl/Tk man](http://www.tcl.tk/man/tcl8.5/TkCmd/event.htm#M41) pages. – Bill Mar 04 '13 at 02:32

3 Answers3

85
def onselect(evt):
    # Note here that Tkinter passes an event object to onselect()
    w = evt.widget
    index = int(w.curselection()[0])
    value = w.get(index)
    print('You selected item %d: "%s"' % (index, value))

lb = Listbox(frame, name='lb')
lb.bind('<<ListboxSelect>>', onselect)
themadmax
  • 2,344
  • 1
  • 31
  • 36
Pierre-Jean Coudert
  • 9,109
  • 10
  • 50
  • 59
  • 5
    Minor point, but this only prints the first of the selected entries. If you've multiple selections, try something like `print 'You selected items: %s'%[w.get(int(i)) for i in w.curselection()]` – drevicko Nov 02 '13 at 00:17
  • 1
    In Python 3.6.5, `int(w.curselection()[0])` can be replaced with `w.curselection()[0]` because it already returns an object of type int. Notice that I didn't try this with any other Python version. – ismailarilik Jun 04 '18 at 12:21
71

You can bind to the <<ListboxSelect>> event. This event will be generated whenever the selection changes, whether it changes from a button click, via the keyboard, or any other method.

Here's a simple example which updates a label whenever you select something from the listbox:

import tkinter as tk

root = tk.Tk()
label = tk.Label(root)
listbox = tk.Listbox(root)
label.pack(side="bottom", fill="x")
listbox.pack(side="top", fill="both", expand=True)

listbox.insert("end", "one", "two", "three", "four", "five")

def callback(event):
    selection = event.widget.curselection()
    if selection:
        index = selection[0]
        data = event.widget.get(index)
        label.configure(text=data)
    else:
        label.configure(text="")

listbox.bind("<<ListboxSelect>>", callback)

root.mainloop()

screenshot

This event is mentioned in the canonical man page for listbox. All predefined virtual events can be found on the bind man page.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • 1
    @RobotGymnast Try (The Tcl/Tk man pages)[http://www.tcl.tk/man/tcl8.5/TkCmd/event.htm#M41] (from Bill's answer below) – drevicko Nov 02 '13 at 00:11
4

I had the problem that I needed to get the last selected item in a listbox with selectmode=MULTIPLE. In case someone else has the same problem, here is what I did:

lastselectionList = []
def onselect(evt):
    # Note here that Tkinter passes an event object to onselect()
    global lastselectionList
    w = evt.widget
    if lastselectionList: #if not empty
    #compare last selectionlist with new list and extract the difference
        changedSelection = set(lastselectionList).symmetric_difference(set(w.curselection()))
        lastselectionList = w.curselection()
    else:
    #if empty, assign current selection
        lastselectionList = w.curselection()
        changedSelection = w.curselection()
    #changedSelection should always be a set with only one entry, therefore we can convert it to a lst and extract first entry
    index = int(list(changedSelection)[0])
    value = w.get(index)
    tkinter.messagebox.showinfo("You selected ", value)
listbox = tk.Listbox(frame,selectmode=tk.MULTIPLE)
listbox.bind('<<ListboxSelect>>', onselect)
listbox.pack()
Alex
  • 2,784
  • 2
  • 32
  • 46