How to create a tree view with checkboxes in Python

后端 未结 2 2009
抹茶落季
抹茶落季 2020-11-28 13:19

I\'ve been using Tkinter and Tix to write a small program. I\'m at a point where I need a tree view with checkboxes (checkbuttons) so I can select items from the tree view.

相关标签:
2条回答
  • 2020-11-28 14:09

    I made a treeview class with checkboxes inheriting ttk.Treeview, but the checkboxes are not ttk.Checkbutton but images of checked, unchecked and tristate checkboxes.

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

    An improved version of CheckboxTreeview is available in the ttkwidgets module.

    0 讨论(0)
  • 2020-11-28 14:16

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