Python Tkinter:树选择 [英] Python Tkinter: Tree selection

查看:191
本文介绍了Python Tkinter:树选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在Canvas中左右创建了两个带有idlelib.TreeWidget的树。



我也可以打印出树节点的名称,点击,但我需要的是双击一个树节点将使一个树节点可见和选择。



我有一个简单的例子。如果双击左侧的level1,右侧的ccc应该可见并自动选择。



请运行以下代码:

 从Tkinter导入Tk,Frame,BOTH,Canvas 
从xml.dom.minidom导入parseString
从idlelib.TreeWidget导入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 )for node in children]
itemlist = [item for 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>
'''
类应用程序(框架):

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 = row = 0,sticky ='NSWE')
node2 = TreeNode(self.canvas2,None,item2)
node2.update()

self.pack(fill = BOTH ,expand = True)

def main():
root = Tk()
应用程序(root)
root.mainloop()

if __name__ =='__main__':
main()


解决方案

首先,你的双击回调必须知道你的TreeNode node2 (我可以想到全局变量,属性在DomTreeItem或bounce到另一个组件)。



然后你可以依赖TreeNode的 expand()方法,读取 children 属性,并依次展开,直到您想要的元素。请注意, children 属性只在节点扩展后填充。



1。快速回答



您提供的示例的快速和脏的解决方案

  class DomTreeItem(TreeItem):
def OnDoubleClick(self):
if self.GetText()==level1:
node2.expand()
node2.children [ 0] .expand()
node2.children [0] .children [0] .select()

[...] ):
def __init __(self,parent):
global node2



2 。通用解决方案



这是一个更常见的在树中显示任意项的方法。

  def reach(node_tree,path):
tokens = path.split(/)
current_node = node_tree
用于tokens中的名称:
如果len (current_node.children)== 0和current_node.state!=expanded:
current_node.expand()
candidates = [child_node.children中child的子节点,如果child.item.GetText = name]
if len(candidates)== 0:
print(did not find'{}'。format(name))
return
current_node = candidates [ 0]
current_node.select()

您可以这样使用

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



3。建筑方案



除了扩展项目的选择外,我还建议您通过DIY观察者建立更清洁的建筑。



DIY观察器



(模仿Tkinter bind tkinter机械,因为生成带有用户数据的事件未正确处理

  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())

专用组件 b
$ b

依赖于上述的覆盖方法。

  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 }



订阅

 类应用程序(框架):
def __init __(self,parent):
[...]

expander = TreeExpander(node2,{
level1 bbb / ccc
})
item.bind(<< TreeDoubleClick>>,expander)



我没有找到idlelib的文档,在这种情况下,你可以尝试看看代码。以下代码段允许您查找托管此模块的文件。

  import idlelib.TreeWidget 
print (idlelib.TreeWidget .__ file__)


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 double-clicking one tree node will make a certain tree node visible and selected.

I have a simple example here. If you double click "level1" on the left hand side, "ccc" on the right hand side should be visible and automatically selected. How do you do that?

Please run the following code:

from Tkinter import Tk, Frame, BOTH, Canvas
from xml.dom.minidom import parseString
from 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) for node in children]
      itemlist = [item for 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, 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__)

这篇关于Python Tkinter:树选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆