canvas - Python Tkinter: Tree selection -
i have created 2 trees idlelib.treewidget in canvas, left , right.
i able print out name of tree node if double-clicked, need double-clicking 1 tree node make tree node visible , selected.
i have simple example here. if double click "level1" on left hand side, "ccc" on right hand side should visible , automatically selected. how do that?
please run following code:
from tkinter import tk, frame, both, canvas xml.dom.minidom import parsestring idlelib.treewidget import treeitem, treenode class domtreeitem(treeitem): def __init__(self, node): self.node = node def gettext(self): node = self.node if node.nodetype == node.element_node: return node.nodename elif node.nodetype == node.text_node: return node.nodevalue def isexpandable(self): node = self.node return node.haschildnodes() def getsublist(self): parent = self.node children = parent.childnodes prelist = [domtreeitem(node) node in children] itemlist = [item item in prelist if item.gettext().strip()] return itemlist def ondoubleclick(self): print self.node.nodename left = ''' <level0> <level1/> </level0> ''' right = ''' <aaa> <bbb> <ccc/> </bbb> </aaa> ''' class application(frame): def __init__(self, parent): frame.__init__(self, parent) self.parent = parent self.parent.geometry('%dx%d+%d+%d' % (800, 300, 0, 0)) self.parent.resizable(0, 0) dom = parsestring(left) item = domtreeitem(dom.documentelement) self.canvas = canvas(self, bg = "cyan") self.canvas.grid(column = 0, row = 0, sticky = 'nswe') node = treenode(self.canvas, none, item) node.update() dom2 = parsestring(right) item2 = domtreeitem(dom2.documentelement) self.canvas2 = canvas(self, bg = "yellow") self.canvas2.grid(column = 1, row = 0, sticky = 'nswe') node2 = treenode(self.canvas2, none, item2) node2.update() self.pack(fill = both, expand = true) def main(): root = tk() application(root) root.mainloop() if __name__ == '__main__': main()
first, double click callback must aware of treenode node2
(i can think of global variable, attribute in domtreeitem or bounce component).
then can rely on expand()
method of treenode, read children
attribute , expand sequentially until element want. note children
attribute populated after node has been expanded.
1. quick answer
quick , dirty solution example have provided
class domtreeitem(treeitem): def ondoubleclick(self): if self.gettext() == "level1": node2.expand() node2.children[0].expand() node2.children[0].children[0].select() [...] class application(frame): def __init__(self, parent): global node2
2. generic solution
here more general method display arbitrary item in tree.
def reach(node_tree, path): tokens = path.split("/") current_node = node_tree name in tokens: if len(current_node.children) == 0 , current_node.state != "expanded": current_node.expand() candidates = [child child in current_node.children if child.item.gettext() == name] if len(candidates) == 0: print("did not find '{}'".format(name)) return current_node = candidates[0] current_node.select()
you might use way
if self.gettext() == "level1": reach(node2, "bbb/ccc")
3. architecture proposal
besides expansion selection of item, propose cleaner architecture through diy observer.
diy observer
(mimic tkinter bind
call not rely on tkinter machinery since generating event user data not handled)
class domtreeitem(treeitem): def __init__(self, node, dbl_click_bindings = none): self.node = node self.dbl_click_bindings = [] if (dbl_click_bindings == none) else dbl_click_bindings [...] def ondoubleclick(self): self.firedblclick() def bind(self, event, callback): '''mimic tkinter bind ''' if (event != "<<treedoubleclick>>"): print("err...") self.dbl_click_bindings.append(callback) def firedblclick(self): callback in self.dbl_click_bindings: callback.double_click(self.gettext())
dedicated component
rely on reach method presented above.
class treeexpander: def __init__(self, node_tree, matching_items): self.node_tree = node_tree self.matching_items = matching_items def double_click(self, item_name): print("double_click ({0})".format(item_name)) if (item_name in self.matching_items): reach(self.node_tree, self.matching_items[item_name])
subscription
class application(frame): def __init__(self, parent): [...] expander = treeexpander(node2, { "level1": "bbb/ccc" }) item.bind("<<treedoubleclick>>", expander)
i did not find docs idlelib, in case, can try @ code. following snippet allows find file host module.
import idlelib.treewidget print(idlelib.treewidget.__file__)
Comments
Post a Comment