2

When you want to select an item in a Treeview, you usually use the double-click:

def print_element(event):
    print(my_treeview.selection()[0])
my_treeview.bind("<Double-1>", print_element)

Today I tried to do the same but using a single click instead:

my_treeview.bind("<Button-1>", print_element)

But it wouldn't work. The output was just an empty tuple. I started to search online for an explanation... why is it not working?

EDIT: My goal was actually to do something every time a treeview item was selected.

  • I proposed a solution myself using the identify() function of Tkinter
  • Another user proposed to use the Tkinter callback <ButtonRelease-1> which is much more appropriate
  • Finally, a third user focused his answer on using the Tkinter callback <<TreeviewSelect>>, which is for sure the best option
Federico Dorato
  • 710
  • 9
  • 27
  • Does this answer your question? [tkinter-treeview-click-event-for-selected-item](https://stackoverflow.com/questions/40533812) – stovfl Apr 24 '20 at 10:04
  • You should bind on `` or `<>` instead. – acw1668 Apr 24 '20 at 10:09
  • @acw1668 I didn't think about using that event in that way. What you suggest is probably the pythonic way to do it. If you leave it an answer, I will accept yours – Federico Dorato Apr 24 '20 at 10:26
  • Are you asking how to _select_ an item in a treeview on click? Treeview does that automatically for you. Or, are you asking how to run a function whenever something is selected in the Treeview? – Bryan Oakley Apr 24 '20 at 13:25
  • @BryanOakley my goal is to obtain a specific value from the selected item, in the same moment it is selected, without a need for the doubleclick – Federico Dorato Apr 25 '20 at 18:26

3 Answers3

4

The reason it doesn't work the way you expect is because your custom single-click binding happens before the default behavior. So, when your single-click is processed, that happens before an item is selected. The second time you click, your function will print the previously selected item.

If you want to have a function called when an item is selected, you should bind to <<TreeviewSelect>>, which will fire immediately after the user selects an item with a single click or via the keyboard.

The default behavior of a treeview supports selecting multiple items at once, so the following code will print out the text of all of the selected items as a list, even if only a single item is selected. You can, of course, modify this to only print out the first selected item if you so desire.

def print_element(event):
    tree = event.widget
    selection = [tree.item(item)["text"] for item in tree.selection()]
    print("selected items:", selection)

tree.bind("<<TreeviewSelect>>", print_element)
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
1

It is because the selection is not set yet when the <Button-1> (it is the same as <ButtonPress-1>, i.e. when the mouse button 1 is pressed and not released) event callback is called.

You should bind on <ButtonRelease-1> or <<TreeviewSelect>> instead as the selection is set when the event callback is being executed.

acw1668
  • 40,144
  • 5
  • 22
  • 34
  • I have to pick Bryan answer because he provided a code solution, and focused his answer to TreeviewSelect (I didn't even pay attention to it when you mentioned it). Still, kudos for bringing up ButtonRelease-1 – Federico Dorato Apr 27 '20 at 03:30
0

Why it doesn't work

When you click an item in a treeview, that item is still not in a SELECTED status in the moment the callback is activated. You are changing the status in that very moment.

Using a double-click, the first click change the status, and at the second click you are activating your callback, so the status has already been changed.

How can it work

Kudos to this website

In short,

def print_element(event):
    print(my_treeview.identify('item', e.x, e.y))
my_treeview.bind("<Button-1>", print_element)

This time, print_element() will check the coordinates of the mouse, and will discover the selected item check what is under the mouse. Nice and clean!

Federico Dorato
  • 710
  • 9
  • 27