Python Tkinter: Tree selection

自作多情 提交于 2019-11-29 08:05:25
FabienAndre

First, your double click callback must be aware of your TreeNode node2 (I can think of global variable, attribute in DomTreeItem or bounce to another component).

Then you can rely on expand() method of TreeNode, read the children attribute and expand sequentially until the element you want. Note that children attribute is only populated after the node has been expanded.

1. Quick answer

Quick and dirty solution for the example you 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 is a more general method to display an arbitrary item in a tree.

def reach(node_tree, path):
   tokens = path.split("/")
   current_node = node_tree
   for name in tokens:
      if len(current_node.children) == 0 and current_node.state != "expanded":
         current_node.expand()
      candidates = [child for 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 it this way

if self.GetText() == "level1":
    reach(node2, "bbb/ccc")

3. Architecture proposal

Besides the expansion an selection of an item, I propose you a cleaner architecture through a DIY observer.

DIY Observer

(mimic the Tkinter bind call but does not rely on tkinter machinery since generating event with user data is not properly 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):
      for callback in self.dbl_click_bindings:
         callback.double_click(self.GetText())

Dedicated component

Rely on the 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 for idlelib, in this case, you can try to look at the code. The following snippet allows you to find which file host this module.
import idlelib.TreeWidget
print(idlelib.TreeWidget.__file__)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!