";require "../templates/head_jq_bs4.php";echo "
";$img_path="..";require "top-link-tkinter.php";require "templates/top_bs4.php";echo "ttk.Treeview displays structured data as a table, a hierarchical tree, or a combination of both. Each item can contain a tree label, optional child items and values displayed across additional columns.
Treeview is useful for displaying database records, file structures, invoices, reports, spreadsheet data and other collections where users need to view or select rows.
show='headings' for a table-style display. Use show='tree headings' when parent-child relationships and expandable nodes are required.Treeview belongs to Tkinter's themed widget set, so import ttk.
import tkinter as tkfrom tkinter import ttkroot=tk.Tk()root.geometry('450x250')root.title('Tkinter Treeview - plus2net')tree=ttk.Treeview(root, columns=('id', 'name'), show='headings')tree.grid(row=0, column=0, padx=20, pady=20)tree.heading('id', text='ID')tree.heading('name', text='Name')tree.column('id', width=80, anchor='center')tree.column('name', width=180)tree.insert('', tk.END, values=(1, 'Alex'))tree.insert('', tk.END, values=(2, 'Ravi'))tree.insert('', tk.END, values=(3, 'Ron'))root.mainloop()This creates a simple two-column table.

Treeview has a special built-in column named #0. This is the tree column.
It can display:
text,The columns specified with columns= are additional data columns.
tree=ttk.Treeview(root, columns=('id', 'name'), show='tree headings')tree.heading('#0', text='Category')tree.heading('id', text='ID')tree.heading('name', text='Name')tree.insert('', tk.END, text='Student', values=(1, 'Alex'))Here:
text='Student'is displayed in #0, while:
values=(1, 'Alex')fills the additional columns.
#0 exists even when it is hidden by show='headings'.| show Value | Result |
|---|---|
'tree' | Displays the tree column #0 but hides headings. |
'headings' | Displays headings and data columns while hiding #0. |
'tree headings' | Displays both the tree column and headings. This is the normal default view. |
'' | Hides both the tree column and headings. |
tree['show']='headings'tree['show']='tree headings'
The basic syntax is:
tree.insert(parent, index, iid=None, text='', values=())For a top-level row, use an empty string as the parent.
item_id=tree.insert('', tk.END, values=(1, 'Alex'))print(item_id)insert() returns the new Treeview item identifier, or iid.
You can also provide your own unique item ID.
tree.insert('', tk.END, iid='student_1', values=(1, 'Alex'))iid identifies the Treeview item. It does not have to be the same as the primary key in MySQL or SQLite. Keep the two concepts separate unless deliberately using the database key as the Treeview ID.A parent item can contain one or more child items.
parent_id=tree.insert('', tk.END, text='Languages', open=True)tree.insert(parent_id, tk.END, text='Python')tree.insert(parent_id, tk.END, text='PHP')tree.insert(parent_id, tk.END, text='JavaScript')The first argument of insert() determines the parent.
''means a top-level item.
A real item ID such as:
parent_idcreates a child under that item.
Treeview Parent-Child NodesUse item() to get all information stored for an item.
data=tree.item(item_id)print(data)Read only the row values:
values=tree.item(item_id, 'values')print(values)If the Treeview has named columns:
name=tree.set(item_id, 'name')print(name)This is often clearer than relying on a numeric position inside values.
selection() returns a tuple containing the selected item IDs.
selected=tree.selection()print(selected)With one selected row, an example result may look like:
('I001',)selected=tree.selection()if selected: item_id=selected[0] print(tree.item(item_id, 'values'))[0]. If no Treeview row is selected, selection() returns an empty tuple.Use:
tree=ttk.Treeview(root, selectmode='extended')Then process all selected IDs:
for item_id in tree.selection(): print(tree.item(item_id, 'values'))Bind <<TreeviewSelect>> to run a function whenever the selection changes.
def row_selected(event): tree=event.widget selected=tree.selection() if not selected: return item_id=selected[0] print('ID:', item_id) print('Values:', tree.item(item_id, 'values'))tree.bind('<<TreeviewSelect>>', row_selected)Using event.widget keeps the callback reusable.
Selection and focus are related but different.
| Method | Meaning |
|---|---|
selection() | Returns the item IDs currently selected. |
focus() | Returns the item that currently has Treeview keyboard focus. |
Read the focus item:
focus_item=tree.focus()Set focus:
tree.focus(item_id)For normal row-selection logic, use selection(). Do not assume that the focus item is always the same as the selected item.
Do not calculate the next row by adding or subtracting from the iid. Item IDs may be strings, database IDs or non-consecutive values.
Instead, use the actual child order returned by get_children().
def move_selection(step): rows=tree.get_children() selected=tree.selection() if not rows: return if not selected: target=rows[0] else: current=selected[0] position=rows.index(current) new_position=max(0, min(position+step, len(rows)-1)) target=rows[new_position] tree.selection_set(target) tree.focus(target) tree.see(target)Buttons:
tk.Button(root, text='Up', command=lambda: move_selection(-1)).grid(row=0, column=0)tk.Button(root, text='Down', command=lambda: move_selection(1)).grid(row=0, column=1)move(item, parent, index).
Treeview does not provide built-in spreadsheet-style cell editing. However, an application's controls can read a selected row and update its values.
def update_name(): selected=tree.selection() if not selected: return item_id=selected[0] values=list(tree.item(item_id, 'values')) values[1]=name_entry.get() tree.item(item_id, values=values)This preserves the other column values and changes only the required position.
When named columns are used, this is simpler:
tree.set(item_id, 'name', name_entry.get())For a specific field, set() is often clearer than rebuilding the complete values sequence.
selected=tree.selection()if selected: tree.delete(selected[0])selected=tree.selection()if selected: tree.delete(*selected)tree.delete(*tree.get_children())Deleting a parent also deletes its descendants from the Treeview.
delete() removes items from the Treeview widget. It does not delete records from MySQL, SQLite, Excel, Google Sheets or another original data source unless your code also updates that source.If an item should disappear without being destroyed:
tree.detach(item_id)The item still exists and can later be attached again with move().
get_children() without a parent returns the top-level item IDs.
for item_id in tree.get_children(): print(tree.item(item_id, 'values'))names=[]for item_id in tree.get_children(): names.append(tree.set(item_id, 'name'))print(names)Using column names makes the code easier to understand than relying on positions such as values[1].
children=tree.get_children(parent_id)This returns only the direct children of that parent.
tree.selection_set(item_id)tree.focus(item_id)tree.see(item_id)A common combination is:
tree.selection_set(item_id)tree.focus(item_id)tree.see(item_id)tree.selection_add(item_id)tree.selection_remove(item_id)tree.selection_remove(tree.selection())| Option | Purpose | Example |
|---|---|---|
columns | Defines additional data column identifiers. | columns=('id','name') |
displaycolumns | Controls which data columns and their display order are visible. | displaycolumns=('name','id') |
height | Requested number of visible rows. | height=10 |
padding | Adds internal widget padding. | padding=5 |
selectmode | Selection behavior: browse, extended or none. | selectmode='extended' |
show | Controls the tree column and headings. | show='headings' |
style | Name of the ttk style applied to the widget. | style='Custom.Treeview' |
cursor | Mouse cursor shown over the widget. | cursor='hand2' |
takefocus | Controls keyboard focus traversal. | takefocus=True |
xscrollcommand | Connects horizontal scrolling. | xscrollcommand=hs.set |
yscrollcommand | Connects vertical scrolling. | yscrollcommand=vs.set |
Suppose Treeview contains:
tree['columns']=('id', 'name', 'class', 'mark')Display only name and mark:
tree['displaycolumns']=('name', 'mark')The underlying values still exist; only their display is changed.
| Method | Purpose |
|---|---|
insert(parent,index,...) | Create and return a new Treeview item. |
item(item,...) | Read or update item options such as text, values, open and tags. |
set(item,column,value) | Read or update individual data-column values. |
delete(*items) | Delete items and their descendants. |
detach(*items) | Hide items without destroying them. |
exists(item) | Check whether an item ID exists. |
get_children(item=None) | Return direct child item IDs. |
parent(item) | Return an item's parent ID. |
index(item) | Return its position among siblings. |
next(item) | Return the next sibling ID. |
prev(item) | Return the previous sibling ID. |
move(item,parent,index) | Move or reattach an item. |
selection() | Return selected item IDs. |
selection_set() | Replace the current selection. |
selection_add() | Add items to the current selection. |
selection_remove() | Remove items from the selection. |
selection_toggle() | Toggle selection state. |
focus() | Get or set the focus item. |
see(item) | Open ancestors if needed and scroll until the item is visible. |
column() | Read or configure column properties. |
heading() | Read or configure a column heading. |
bbox() | Return an item's or cell's bounding box when visible. |
identify_row(y) | Return the item ID at a y-coordinate. |
identify_column(x) | Return the display column at an x-coordinate. |
identify_region(x,y) | Identify whether coordinates are over a heading, separator, tree or cell. |
tag_configure() | Configure appearance associated with a tag. |
tag_bind() | Bind events to tagged items. |
tag_has() | Check which items contain a tag. |
if tree.exists('student_1'): print('Item exists')position=tree.index(item_id)previous_item=tree.prev(item_id)next_item=tree.next(item_id)Treeview does not automatically wrap long cell text to calculate a different height for each row. One approach is to insert newline characters and increase the Treeview style's common row height.
import tkinter as tkfrom tkinter import ttkimport textwrapdef wrap_text(text, length=20): return '\n'.join(textwrap.wrap(text, length))root=tk.Tk()style=ttk.Style()style.configure('Treeview', rowheight=60)tree=ttk.Treeview(root, columns=('one', 'two'), show='headings', height=3)tree.heading('one', text='Column 1')tree.heading('two', text='Column 2')tree.column('one', width=120)tree.column('two', width=120)tree.insert('', tk.END, values=(wrap_text('This is long text I want to wrap'), wrap_text('This text is also longer than the column')))tree.insert('', tk.END, values=('No wrap', 'No wrap'))tree.pack(padx=20, pady=20)root.mainloop()
rowheight applies to Treeview rows generally; it is not automatically calculated separately for each row.
Large tables usually require a vertical Scrollbar.
vs=ttk.Scrollbar(root, orient='vertical', command=tree.yview)tree.configure(yscrollcommand=vs.set)tree.grid(row=0, column=0, sticky='nsew')vs.grid(row=0, column=1, sticky='ns')Treeview with MySQL Records and Scrollbar A horizontal scrollbar is useful when the combined column width is wider than the available Treeview area.
tree.column('name', width=250, stretch=False)hs=ttk.Scrollbar(root, orient='horizontal', command=tree.xview)tree.configure(xscrollcommand=hs.set)hs.grid(row=1, column=0, sticky='ew')stretch=False is useful when you want a column to retain its configured width instead of expanding to consume available space.
Treeview displays the data supplied by your Python program. The source can be a Python collection, database query, spreadsheet, Google Sheet or Pandas DataFrame.

Read Excel rows with OpenPyXL and insert the values into Treeview.
Excel Data in Treeview
Collect spreadsheet data using pygsheets and display the records through Treeview.
Google Sheets Data in TreeviewDatabase records can be displayed as Treeview rows and connected to update, delete and pagination operations.
Display MySQL RecordsMySQL PaginationDelete MySQL RecordsUpdate MySQL RecordAfter learning the basic widget, choose the next tutorial according to what you want the Treeview to do.
Avoid:
item_id=tree.selection()[0]Use:
selected=tree.selection()if selected: item_id=selected[0]focus() and selection() represent different Treeview states.
Do not navigate rows by incrementing an iid. Use get_children(), index(), next() or prev().
#0 is the special tree column. Columns declared with columns= are separate data columns.
Treeview displays values but does not include built-in cell editors. Update values with item() or set(), or create an Entry-based editing interface.
Treeview and the original data source must be synchronized explicitly.
This works:
tree.item(item_id, 'values')[1]but with named columns this is often clearer:
tree.set(item_id, 'name')Clear the current selection with:
tree.selection_remove(tree.selection())Treeview does not automatically resize individual rows based on wrapped cell text. Insert line breaks and configure an appropriate row height when needed.
ttk.Treeview displays tabular and hierarchical data.#0 is the special tree column.columns defines additional data columns.show='headings' creates a table-style display.show='tree headings' displays both hierarchy and headings.insert() creates items and returns their item ID.selection() returns selected item IDs as a tuple.focus() and selection() are not the same thing.<<TreeviewSelect>> detects selection changes.item() reads or updates complete item information.set() is convenient for individual data columns.get_children() returns child item IDs.parent() returns an item's parent.next() and prev() navigate sibling items.move() changes an item's parent or position.selection_set(), focus() and see() are useful together for programmatic navigation.delete() destroys Treeview items and descendants.detach() hides items without destroying them.xview and yview.