0
Problem
How to create a button bind class in ttk. Treeview?
Sample Code
When programming the main class, which defines Treeview and then create another class that defines bindings and events. It is not possible to create these bindings that are in another class, only in the same. As the following example:
import Tkinter
import ttk
class clique_bind(ttk.Treeview):
def __init__(self, *args, **kwargs):
ttk.Treeview.__init__(self, *args, **kwargs)
print self.widgetName
# create the entry on init but does no show it
self.bind("<Key>", self._qual_tecla)
def _qual_tecla(self, event):
print("Tecla: " + event.keysym)
class principal(Tkinter.Tk):
def __init__(self, parent):
Tkinter.Tk.__init__(self, parent)
self.parent = parent
tree = ttk.Treeview()
tree["columns"] = ("one", "two")
tree.column("one", width=100)
tree.column("two", width=100)
tree.heading("one", text="coulmn A")
tree.heading("two", text="column B")
tree.insert("", 0, text="Line 1", values=("1A", "1b"))
id2 = tree.insert("", 1, "dir2", text="Dir 2")
tree.insert(id2, "end", "dir 2", text="sub dir 2", values=("2A", "2B"))
tree.insert("", 3, "dir3", text="Dir 3")
tree.insert("dir3", 3, text=" sub dir 3", values=("3A", " 3B"))
tree.pack()
tree.bind('<Button-3>', self._teste_direito)
clique_bind(tree)
def _teste_direito(self, event):
print("Direito")
if __name__ == "__main__":
App = principal(None)
App.mainloop()
When performing the right mouse click bind on the main class, it is possible to check print("Direito")
. But by creating the class clique_bind
, where capturing keyboard buttons in another Class is not possible.
Complete Code
The complete code of what is being programmed, to better understand the problem.
Where the code to list directories used is based in the Tkinter documentation and searching on treeview in this answer. Some changes were made.
"""A directory browser using Ttk Treeview.
Based on the demo found in Tk 8.5 library/demos/browse
https://svn.python.org/projects/stackless/trunk/Demo/tkinter/ttk/dirbrowser.py
Search based on: https://stackoverflow.com/a/17271593/7690982
"""
import Tkinter
import ttk
import os
import glob
class SearchableTreeview(ttk.Treeview):
def __init__(self, *args, **kwargs):
ttk.Treeview.__init__(self, *args, **kwargs)
# create the entry on init but does no show it
self._toSearch = Tkinter.StringVar()
self.focus()
self.entry = Tkinter.Entry(self, textvariable=self._toSearch)
self.bind("<Key>", self._keyOnTree)
self._toSearch.trace_variable("w", self._search)
self.entry.bind("<Return>", self._hideEntry)
self.entry.bind("<Escape>", self._hideEntry)
print("init")
def _keyOnTree(self, event):
print("keyontree")
self.entry.place(relx=1, anchor=Tkinter.NE)
if event.char.isalpha():
self.entry.insert(Tkinter.END, event.char)
self.entry.focus_set()
def _hideEntry(self, event):
print("hideentry")
self.entry.delete(0, Tkinter.END)
self.entry.place_forget()
self.focus_set()
def _search(self, *args):
print("search")
pattern = self._toSearch.get()
#avoid search on empty string
if len(pattern) > 0:
self.search(pattern)
def search(self, pattern, item=''):
children = self.get_children(item)
for child in children:
text = self.item(child, 'text')
if text.lower().startswith(pattern.lower()):
self.selection_set(child)
self.see(child)
return True
else:
res = self.search(pattern, child)
if res:
return True
class ListagemDir(Tkinter.Tk):
def __init__(self, parent):
Tkinter.Tk.__init__(self, parent)
self.parent = parent
self.DirTree()
def DirTree(self):
vsb = ttk.Scrollbar(orient="vertical")
hsb = ttk.Scrollbar(orient="horizontal")
tree = ttk.Treeview(columns=("fullpath", "type", "size"),
displaycolumns="size", yscrollcommand=lambda f, l: self.autoscroll(vsb, f, l),
xscrollcommand=lambda f, l: self.autoscroll(hsb, f, l))
vsb['command'] = tree.yview
hsb['command'] = tree.xview
tree.heading("#0", text="Directory Structure", anchor='w')
tree.heading("size", text="File Size", anchor='w')
tree.column("size", stretch=0, width=100)
self.populate_roots(tree)
tree.bind('<<TreeviewOpen>>', self.update_tree)
tree.bind('<Double-Button-1>', self.change_dir)
# Arrange the tree and its scrollbars in the toplevel
tree.grid(column=0, row=0, sticky='nswe')
vsb.grid(column=1, row=0, sticky='ns')
hsb.grid(column=0, row=1, sticky='ew')
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
tree.bind("<Button-3>", self._press3)
searchable = SearchableTreeview(tree)
def populate_tree(self, tree, node):
if tree.set(node, "type") != 'directory':
return
path = tree.set(node, "fullpath")
tree.delete(*tree.get_children(node))
parent = tree.parent(node)
special_dirs = [] if parent else glob.glob('.') + glob.glob('..')
for p in special_dirs + os.listdir(path):
ptype = None
p = os.path.join(path, p).replace('\\', '/')
if os.path.isdir(p): ptype = "directory"
elif os.path.isfile(p): ptype = "file"
fname = os.path.split(p)[1]
id = tree.insert(node, "end", text=fname, values=[p, ptype])
if ptype == 'directory':
if fname not in ('.', '..'):
tree.insert(id, 0, text="dummy")
tree.item(id, text=fname)
elif ptype == 'file':
size = os.stat(p).st_size
tree.set(id, "size", "%d bytes" % size)
def populate_roots(self, tree):
dir = os.path.abspath('.').replace('\\', '/')
node = tree.insert('', 'end', text=dir, values=[dir, "directory"])
self.populate_tree(tree, node)
def update_tree(self, event):
tree = event.widget
self.populate_tree(tree, tree.focus())
def change_dir(self, event):
tree = event.widget
node = tree.focus()
if tree.parent(node):
path = os.path.abspath(tree.set(node, "fullpath"))
if os.path.isdir(path):
os.chdir(path)
tree.delete(tree.get_children(''))
self.populate_roots(tree)
def autoscroll(self, sbar, first, last):
"""Hide and show scrollbar as needed."""
first, last = float(first), float(last)
if first <= 0 and last >= 1:
sbar.grid_remove()
else:
sbar.grid()
sbar.set(first, last)
def _press3(self, event):
print("Tipo de Evento: " + event.keysym)
if __name__ == "__main__":
App = ListagemDir(None)
App.mainloop()
Trying
It was possible to perform the complete code in the same class, but I’m not getting it in different classes. Could be some error of class fundamentals or even Tkinter syntax.
"""A directory browser using Ttk Treeview.
Based on the demo found in Tk 8.5 library/demos/browse
https://svn.python.org/projects/stackless/trunk/Demo/tkinter/ttk/dirbrowser.py
Search based on: https://stackoverflow.com/a/17271593/7690982
"""
import os
import glob
import Tkinter
import ttk
class ListagemDir(Tkinter.Tk):
def __init__(self, parent):
Tkinter.Tk.__init__(self, parent)
self.parent = parent
self.DirTree()
def DirTree(self):
vsb = ttk.Scrollbar(orient="vertical")
hsb = ttk.Scrollbar(orient="horizontal")
tree = ttk.Treeview(columns=("fullpath", "type", "size"),
displaycolumns="size", yscrollcommand=lambda f, l: self.autoscroll(vsb, f, l),
xscrollcommand=lambda f, l: self.autoscroll(hsb, f, l))
vsb['command'] = tree.yview
hsb['command'] = tree.xview
tree.heading("#0", text="Directory Structure", anchor='w')
tree.heading("size", text="File Size", anchor='w')
tree.column("size", stretch=0, width=100)
self.populate_roots(tree)
tree.bind('<<TreeviewOpen>>', self.update_tree)
tree.bind('<Double-Button-1>', self.change_dir)
# Arrange the tree and its scrollbars in the toplevel
tree.grid(column=0, row=0, sticky='nswe')
vsb.grid(column=1, row=0, sticky='ns')
hsb.grid(column=0, row=1, sticky='ew')
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
tree.bind("<Button-3>", self._press3)
self._toSearch = Tkinter.StringVar()
tree.focus()
self.entry = Tkinter.Entry(tree, textvariable = self._toSearch)
tree.bind("<Key>", self._keyOnTree)
self._toSearch.trace_variable("w", self._search)
self.entry.bind("<Return>", self._hideEntry)
self.entry.bind("<Escape>", self._hideEntry)
print("init")
def _keyOnTree(self, event):
print("keyontree")
self.entry.place(relx=1, anchor=Tkinter.NE)
if event.char.isalpha():
self.entry.insert(Tkinter.END, event.char)
self.entry.focus_set()
def _hideEntry(self, event):
print("hideentry")
self.entry.delete(0, Tkinter.END)
self.entry.place_forget()
self.focus_set()
def _search(self, *args):
print("search")
pattern = self._toSearch.get()
#avoid search on empty string
if len(pattern) > 0:
self.search(pattern)
def search(self, pattern, item=''):
widgets_children = self.winfo_children()
#print widgets_children
for widget_child in widgets_children:
if isinstance(widget_child, ttk.Treeview):
tree = widget_child
children = tree.get_children(item)
for child in children:
text = tree.item(child, 'text')
if text.lower().startswith(pattern.lower()):
tree.selection_set(child)
tree.see(child)
return True
else:
res = self.search(pattern, child)
if res:
return True
def populate_tree(self, tree, node):
if tree.set(node, "type") != 'directory':
return
path = tree.set(node, "fullpath")
tree.delete(*tree.get_children(node))
parent = tree.parent(node)
special_dirs = [] if parent else glob.glob('.') + glob.glob('..')
for p in special_dirs + os.listdir(path):
ptype = None
p = os.path.join(path, p).replace('\\', '/')
if os.path.isdir(p): ptype = "directory"
elif os.path.isfile(p): ptype = "file"
fname = os.path.split(p)[1]
id = tree.insert(node, "end", text=fname, values=[p, ptype])
if ptype == 'directory':
if fname not in ('.', '..'):
tree.insert(id, 0, text="dummy")
tree.item(id, text=fname)
elif ptype == 'file':
size = os.stat(p).st_size
tree.set(id, "size", "%d bytes" % size)
def populate_roots(self, tree):
dir = os.path.abspath('.').replace('\\', '/')
node = tree.insert('', 'end', text=dir, values=[dir, "directory"])
self.populate_tree(tree, node)
def update_tree(self, event):
tree = event.widget
self.populate_tree(tree, tree.focus())
def change_dir(self, event):
tree = event.widget
node = tree.focus()
if tree.parent(node):
path = os.path.abspath(tree.set(node, "fullpath"))
if os.path.isdir(path):
os.chdir(path)
tree.delete(tree.get_children(''))
self.populate_roots(tree)
def autoscroll(self, sbar, first, last):
"""Hide and show scrollbar as needed."""
first, last = float(first), float(last)
if first <= 0 and last >= 1:
sbar.grid_remove()
else:
sbar.grid()
sbar.set(first, last)
def _press3(self, event):
print("Tipo de Evento: " + event.keysym)
if __name__ == "__main__":
App = ListagemDir(None)
App.mainloop()
Therefore, if I want to use Treeview as an instance of another class. Is it not possible this way? For within the
class clique_bind
, this line returns True:isinstance(self, ttk.Treeview)
. So I don’t understand why I can’t use self to call the instance method of the other class. It’s really not possible to call?– danieltakeshi
I think you’re confusing the meaning of "instance". At least I’m not understanding what you want to ask, since the phrase "using Treeview as an instance of another class" makes no sense. Check here to make sure we’re talking about the same thing: (the page is from Java, but the definitions are correct for Object Orientation and are the same as in Python: http://www.linhadecodigo.com.br/artigo/pequeno-dicionario-basico-de-orientacao-a-objetos-em-java.aspx )
– jsbueno