2011-02-24 184 views
15

我一直在使用Tkinter和Tix来编写一个小程序。 我现在需要一个带有复选框(checkbuttons)的树形视图,所以我可以从树视图中选择项目。 有没有简单的方法来做到这一点? 我一直在看ttk.Treeview(),它看起来很容易得到树视图,但有没有办法将一个checkbutton插入视图?如何用Python中的复选框创建树视图

一个简单的代码片段将非常感激。

我不限于ttk。任何事情都会做;只要我有一个例子还是不错的文档,我可以让它工作

回答

17

enter image description here

import Tix 

class View(object): 
    def __init__(self, root): 
     self.root = root 
     self.makeCheckList() 

    def makeCheckList(self): 
     self.cl = Tix.CheckList(self.root, browsecmd=self.selectItem) 
     self.cl.pack() 
     self.cl.hlist.add("CL1", text="checklist1") 
     self.cl.hlist.add("CL1.Item1", text="subitem1") 
     self.cl.hlist.add("CL2", text="checklist2") 
     self.cl.hlist.add("CL2.Item1", text="subitem1") 
     self.cl.setstatus("CL2", "on") 
     self.cl.setstatus("CL2.Item1", "on") 
     self.cl.setstatus("CL1", "off") 
     self.cl.setstatus("CL1.Item1", "off") 
     self.cl.autosetmode() 

    def selectItem(self, item): 
     print item, self.cl.getstatus(item) 

def main(): 
    root = Tix.Tk() 
    view = View(root) 
    root.update() 
    root.mainloop() 

if __name__ == '__main__': 
    main() 
+2

是否有可能涉及以某种方式ttk使复选框看起来本机? – pihentagy 2011-05-13 09:25:57

+3

有没有一种方法可以在不使用Tix和Tkinter的情况下创建它? – 2014-04-07 15:27:03

+0

我有Python 2.7,我没有安装Tix,所以我试图找到一个替代方案。 – 2014-04-07 15:45:26

5

我与复选框继承ttk.Treeview一个TreeView类,但复选框没有ttk.Checkbutton但图像选中,未选中和三态复选框。

import tkinter as tk 
import tkinter.ttk as ttk 

class CheckboxTreeview(ttk.Treeview): 
    """ 
     Treeview widget with checkboxes left of each item. 
     The checkboxes are done via the image attribute of the item, so to keep 
     the checkbox, you cannot add an image to the item. 
    """ 

    def __init__(self, master=None, **kw): 
     ttk.Treeview.__init__(self, master, **kw) 
     # checkboxes are implemented with pictures 
     self.im_checked = tk.PhotoImage(file='checked.png') 
     self.im_unchecked = tk.PhotoImage(file='unchecked.png') 
     self.im_tristate = tk.PhotoImage(file='tristate.png') 
     self.tag_configure("unchecked", image=self.im_unchecked) 
     self.tag_configure("tristate", image=self.im_tristate) 
     self.tag_configure("checked", image=self.im_checked) 
     # check/uncheck boxes on click 
     self.bind("<Button-1>", self.box_click, True) 

    def insert(self, parent, index, iid=None, **kw): 
     """ same method as for standard treeview but add the tag 'unchecked' 
      automatically if no tag among ('checked', 'unchecked', 'tristate') 
      is given """ 
     if not "tags" in kw: 
      kw["tags"] = ("unchecked",) 
     elif not ("unchecked" in kw["tags"] or "checked" in kw["tags"] 
        or "tristate" in kw["tags"]): 
      kw["tags"] = ("unchecked",) 
     ttk.Treeview.insert(self, parent, index, iid, **kw) 

    def check_descendant(self, item): 
     """ check the boxes of item's descendants """ 
     children = self.get_children(item) 
     for iid in children: 
      self.item(iid, tags=("checked",)) 
      self.check_descendant(iid) 

    def check_ancestor(self, item): 
     """ check the box of item and change the state of the boxes of item's 
      ancestors accordingly """ 
     self.item(item, tags=("checked",)) 
     parent = self.parent(item) 
     if parent: 
      children = self.get_children(parent) 
      b = ["checked" in self.item(c, "tags") for c in children] 
      if False in b: 
       # at least one box is not checked and item's box is checked 
       self.tristate_parent(parent) 
      else: 
       # all boxes of the children are checked 
       self.check_ancestor(parent) 

    def tristate_parent(self, item): 
     """ put the box of item in tristate and change the state of the boxes of 
      item's ancestors accordingly """ 
     self.item(item, tags=("tristate",)) 
     parent = self.parent(item) 
     if parent: 
      self.tristate_parent(parent) 

    def uncheck_descendant(self, item): 
     """ uncheck the boxes of item's descendant """ 
     children = self.get_children(item) 
     for iid in children: 
      self.item(iid, tags=("unchecked",)) 
      self.uncheck_descendant(iid) 

    def uncheck_ancestor(self, item): 
     """ uncheck the box of item and change the state of the boxes of item's 
      ancestors accordingly """ 
     self.item(item, tags=("unchecked",)) 
     parent = self.parent(item) 
     if parent: 
      children = self.get_children(parent) 
      b = ["unchecked" in self.item(c, "tags") for c in children] 
      if False in b: 
       # at least one box is checked and item's box is unchecked 
       self.tristate_parent(parent) 
      else: 
       # no box is checked 
       self.uncheck_ancestor(parent) 

    def box_click(self, event): 
     """ check or uncheck box when clicked """ 
     x, y, widget = event.x, event.y, event.widget 
     elem = widget.identify("element", x, y) 
     if "image" in elem: 
      # a box was clicked 
      item = self.identify_row(y) 
      tags = self.item(item, "tags") 
      if ("unchecked" in tags) or ("tristate" in tags): 
       self.check_ancestor(item) 
       self.check_descendant(item) 
      else: 
       self.uncheck_descendant(item) 
       self.uncheck_ancestor(item) 



if __name__ == '__main__': 
    root = tk.Tk() 
    t = CheckboxTreeview(root, show="tree") 
    t.pack() 
    t.insert("", 0, "1", text="1") 
    t.insert("1", "end", "11", text="1") 
    t.insert("1", "end", "12", text="2") 
    t.insert("12", "end", "121", text="1") 
    t.insert("12", "end", "122", text="2") 
    t.insert("122", "end", "1221", text="1") 
    t.insert("1", "end", "13", text="3") 
    t.insert("13", "end", "131", text="1") 
    root.mainloop() 

CheckboxTreeview的改进版本是ttkwidgets模块中提供。

+0

这个想法很好,但我不确定它在“Treeview”中的某些条目之后如何扩展。即使图像很小,它仍然需要一小块内存。 – rbaleksandar 2017-08-07 19:12:47

+0

@rbaleksandar我明白你的观点,它不适用于大型树木,但如果你没有数百种物品,它会比Tix树更好。 – 2017-08-08 07:58:01

+0

为什么这不是一个可扩展的解决方案?图像是否复制到每个treenode?我希望只有图像数据的参考是沿节点共享的。所以内存中只有2张图片。或者我错了? – Hatatister 2017-09-20 16:21:02