5

I created a ttk/Treeview Widget in Tkinter using Python 3. I would like to connect an object to its name which is listed in the tree view. To illustrate this I created following example.

import tkinter as tk
from tkinter import ttk

class myclass:
    def __init__(self, name, value):
        self.name=name
        self.value=value

class maintree(ttk.Treeview):
    def __init__(self, master):        
        super().__init__(master)
        self.master = master
        self.my_objects= [myclass("object"+str(_), _) for _ in range(1,11)]
        for my_object in self.my_objects:
            self.insert("", "end", text=my_object.name)

def main(): 
    root = tk.Tk()
    maintree(root).grid()
    root.mainloop()

if __name__ == '__main__':
    main() 

In this example I would like to get the my_class instance corresponding to the selected name in the treeview to do something (ie, display the value of the currently selected my_class object).

I only know about the item IDs but I don't know how to connect something to an item itself. I have the feeling that I have some misconception about how treeview is supposed to work.

I appreciate your Help!

Benjamin
  • 298
  • 1
  • 12

1 Answers1

2

The insert method has no command option. However, you can tag each inserted item and bind the tag to an event. So, I used the object name as tag and then bound it to execute some method of the object on mouse left click.

import tkinter as tk
from tkinter import ttk

class MyClass:
    def __init__(self, name, value):
        self.name=name
        self.value=value

    def callback(self, event=None):
        # event=None is a trick to be able to call the method both directly and 
        # from a binding (that will pass the event argument to the function)
        print(self.name, self.value)

class MainTree(ttk.Treeview):
    def __init__(self, master):        
        super().__init__(master)
        self.master = master
        self.my_objects= [MyClass("object"+str(_), _) for _ in range(1,11)]
        for my_object in self.my_objects:
            self.insert("", "end", text=my_object.name, tags=(my_object.name,))
            self.tag_bind(my_object.name, '<Button-1>', my_object.callback)

def main(): 
    root = tk.Tk()
    MainTree(root).grid()
    root.mainloop()

if __name__ == '__main__':
    main() 
j_4321
  • 15,431
  • 3
  • 34
  • 61
  • First: Thank you very much! Further: Can I extend this method in order to handle selection changes by other method (for example by using the arrow keys) as well? – Benjamin Jan 25 '17 at 15:58
  • I use `id(my_object)` for the tag name now since this gives my a unique id for every object. Also adding `self.tag_bind(id(my_object), '', my_object.callback)` after the `self.tag_bind...` line lets you carry out the callback by keyboard which comes close to what I asked for in my earlier comment. – Benjamin Jan 25 '17 at 16:44
  • 1
    After looking into the properties of the Treeview widget, I found on http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-Treeview-events.html that "Whenever there is a change in the selection, either by items becoming selected or becoming unselected, the widget generates a “<>” event". So replacing "" by “<>” should do what you want. – j_4321 Jan 25 '17 at 16:46