acdr
acdr

Reputation: 4716

Tkinter listbox's "selection_set" and "activate" temporarily disable extended selecting

A Tkinter Listbox can be made to allow selecting multiple items, though the selectmode configuration. However, if I now programmatically select and activate an entry, then using the shift key in combination with an up or down arrow key press doesn't expand the selection to the item above/below the current, but it only activates that new item, while keeping the old selection.

For example, in the following (Python 2.7) code, I subclass Listbox to allow the Home and End keys to select the first and last item in the list, respectively:

import Tkinter as tk

class MyListbox(tk.Listbox):
    def __init__(self, *args, **kwargs):
        tk.Listbox.__init__(self, *args, **kwargs)
        self.bind("<Home>", lambda *args: self.select(0))
        self.bind("<End>", lambda *args: self.select("end"))

    def select(self, index):
        self.select_clear(0, "end")
        self.selection_set(index)
        self.see(index)
        self.activate(index)

main = tk.Tk()
listbox = MyListbox(main, selectmode="extended")
for x in ["one", "two", "three", "four", "five"]:
    listbox.insert("end", x)
listbox.pack()

tk.mainloop()

This produces a window with a list box in it. If you select the list box and hit "End", the last element (the string "five") is selected. If you now press Shift-Up, then you would expect the strings "four" and "five" to be selected. Instead, "four" is activated (as expected) without being selected, and "five" stays selected.

Why does "four" not get selected in addition to "five"? Can I get around this without having to re-bind the arrow keys and friends?

Note that this behaviour does not happen if I select an item by clicking on it, or by navigating to it with the arrow keys.

Upvotes: 4

Views: 8645

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 385970

You need to also set the anchor by calling self.selection_anchor(index) inside your select method.

def select(self, index):
    self.select_clear(0, "end")
    self.selection_set(index)
    self.see(index)
    self.activate(index)
    self.selection_anchor(index)

Upvotes: 5

Related Questions