Python Tkinter: Tree selection

前端 未结 1 1869
北荒
北荒 2020-12-18 11:19

I have created 2 trees with idlelib.TreeWidget in Canvas, left and right.

I am also able to print out the name of a tree node if double-clicked, but what I need is d

相关标签:
1条回答
  • 2020-12-18 12:09

    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__)
    
    0 讨论(0)
提交回复
热议问题