Josh
Josh

Reputation: 744

Tkinter treeview - Expand all child nodes

In Python 3.7, I need to expand all child nodes when a node is opened. Lets use the following example:

A
--A.1
----A.1.1
--A.2
----A.2.1
----A.2.2
B
--B.1
----B.1.1
--B.2

With this example, when A is expanding in the GUI, all child nodes of A should also be expanded.

As per the official treeview documentation, you can bind the event "<>", which is generated immediately before the selected node is expanded. Knowing this, I can bind the event as such:

tree.bind('<<TreeviewOpen>>', handleOpenEvent)

Now I can write a method to handle the event, using the strategy from this solution like so:

def handleOpenEvent(event):
  tree.item(tree.focus(), open=True) # Tried with and without
  for child in tree.get_children(tree.focus()):
    tree.item(child, open=True)

Whatever I try, this code will NOT expand ALL children on the selected node. I've tried making it so expanding A will expand all B nodes, and that DOES work, but I'm not able to expand all A nodes when A is expanded. It seems like there's some extra underlying things that Treeview is doing that I don't know about. Any thoughts?

Upvotes: 5

Views: 9564

Answers (1)

j_4321
j_4321

Reputation: 16169

You are not far from the solution, what is missing is that you need to recursively open the children of the children in handleOpenEvent(). What I suggest is to write a separate function open_children(parent) that recursively opens the items:

def open_children(parent):
    tree.item(parent, open=True)  # open parent
    for child in tree.get_children(parent):
        open_children(child)    # recursively open children

and then use it in handleOpenEvent():

def handleOpenEvent(event):
    open_children(tree.focus())

Here is the full code:

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
tree = ttk.Treeview(root)
tree.pack()
tree.insert("", "end", "A", text="A")
tree.insert("", "end", "B", text="B")
tree.insert("A", "end", "A.1", text="A.1")
tree.insert("A.1", "end", "A.1.1", text="A.1.1")
tree.insert("A", "end", "A.2", text="A.2")
tree.insert("A.2", "end", "A.2.1", text="A.2.1")
tree.insert("A.2", "end", "A.2.2", text="A.2.2")
tree.insert("B", "end", "B.1", text="B.1")
tree.insert("B", "end", "B.2", text="B.2")
tree.insert("B.1", "end", "B.1.1", text="B.1.1")

def open_children(parent):
    tree.item(parent, open=True)
    for child in tree.get_children(parent):
        open_children(child)

def handleOpenEvent(event):
    open_children(tree.focus())

tree.bind('<<TreeviewOpen>>', handleOpenEvent)
root.mainloop()

Upvotes: 9

Related Questions