Dynamic Tkinter Treeview Columns from Different Data Sources

CSV Excel Pandas MySQL and SQLite as data sources for Tkinter Treeview

A Tkinter Treeview can display data even when the number and names of columns are not known while writing the GUI. We can read the column names from CSV, Excel, Pandas, MySQL, SQLite or another source and create the Treeview columns dynamically.

The useful pattern is the same for every source:

headers=[...]
rows=[...]

configure_treeview(tree, headers, rows)

The data-reading code changes, but the Treeview-building code remains the same.

Sample Student Data: Excel, CSV, MySQL, SQLite and Pandas


Why Create Treeview Columns Dynamically? 🔝

A database query can return a different number of columns depending on the selected fields.

SELECT id, name FROM student
SELECT id, name, class FROM student
SELECT * FROM student

The first query returns two columns, the second returns three, and the third returns all columns in the table.

Instead of hard-coding five Treeview columns, Python can inspect the returned column names and build the interface automatically.

Dynamic creation of Tkinter Treeview columns and headings

Use the Same Data Structure for Every Source 🔝

Regardless of whether the source is CSV, Excel, Pandas or a database, convert the result into:

headers=['id', 'Name', 'Class', 'Mark', 'Gender']

rows=[
    (1, 'Alex', 'Four', 75, 'Male'),
    (2, 'Ravi', 'Three', 65, 'Male')
]

The Treeview function does not need to know where those two objects came from.

Create the Treeview 🔝

import tkinter as tk
from tkinter import ttk

root=tk.Tk()
root.geometry('700x350')
root.title('Dynamic Treeview - plus2net')

tree=ttk.Treeview(root, show='headings', selectmode='browse')
tree.grid(row=0, column=0, sticky='nsew')

show='headings' is appropriate for flat tabular data because the special Treeview column #0 is not required.

selectmode='browse' means that one item can normally be selected at a time. It does not provide scrolling.

Tkinter Treeview Data from CSV and Excel with Dynamic Headers

Reusable Function to Build Dynamic Columns 🔝

The function below clears existing Treeview rows, creates safe internal column identifiers, adds the visible headings and inserts the supplied rows.

def configure_treeview(tree, headers, rows):
    for item in tree.get_children():
        tree.delete(item)

    column_ids=[f'col{i}' for i in range(len(headers))]
    tree['columns']=column_ids
    tree['show']='headings'

    for column_id, heading in zip(column_ids, headers):
        heading_text='' if heading is None else str(heading)
        tree.heading(column_id, text=heading_text)
        tree.column(column_id, width=110, minwidth=60, anchor='center')

    for row in rows:
        values=list(row)
        if len(values)<len(column_ids):
            values+= ['']*(len(column_ids)-len(values))
        tree.insert('', tk.END, values=values[:len(column_ids)])

Why Use col0, col1, col2?

A source can contain duplicate or blank headings:

ID | Name | Mark | Mark |

Using those values directly as Treeview column identifiers can create problems. Instead:

col0
col1
col2
col3
col4

are used internally, while the source headings remain the visible labels.

Why Not Use the First Field as iid?

The old pattern:

tree.insert('', tk.END, iid=row[0], values=row)

assumes that the first value is always unique and non-empty.

For a general-purpose dynamic-data tutorial, it is safer to omit iid and let Treeview generate its own item IDs.

MySQL Database as Data Source 🔝

Using SQLAlchemy, the result provides both column names and rows.

from sqlalchemy import create_engine, text

engine=create_engine('mysql+mysqldb://userid:password@localhost/my_db')

with engine.connect() as conn:
    result=conn.execute(text('SELECT * FROM student'))
    headers=list(result.keys())
    rows=[tuple(row) for row in result]

Use your actual database credentials and the database driver configured for your project.

MySQL Database

Different SQL Queries, Different Treeview Columns

SELECT id, name FROM student

produces two Treeview columns, while:

SELECT id, name, class, mark FROM student

produces four. The rendering function does not change.

SQLite Database as Data Source 🔝

from sqlalchemy import create_engine, text

engine=create_engine('sqlite:///my_db.db')

with engine.connect() as conn:
    result=conn.execute(text('SELECT * FROM student'))
    headers=list(result.keys())
    rows=[tuple(row) for row in result]
SQLite Database
Tkinter Treeview Data from Pandas, MySQL and SQLite

Pandas DataFrame as Data Source 🔝

import pandas as pd

df=pd.read_excel('student.xlsx')
headers=df.columns.tolist()
rows=list(df.itertuples(index=False, name=None))

df.columns.tolist() creates the header list. itertuples() creates the row data without adding the DataFrame index.

Pandas DataFrame

Excel File with OpenPyXL 🔝

from openpyxl import load_workbook

wb=load_workbook('student.xlsx', read_only=True, data_only=True)
ws=wb.active

row_iter=ws.iter_rows(values_only=True)
headers=next(row_iter)
rows=list(row_iter)

wb.close()

The first worksheet row becomes the headings and the remaining rows become Treeview data.

OpenPyXL Excel Tutorials Excel Data in Treeview

CSV File as Data Source 🔝

import csv

with open('student.csv', newline='', encoding='utf-8-sig') as file:
    reader=csv.reader(file)
    headers=next(reader)
    rows=list(reader)

The with statement closes the CSV file automatically after reading.

Start with a Simple Python List 🔝

Before connecting a real data source, the dynamic logic can be tested with ordinary Python lists.

headers=['id', 'Name', 'Class', 'Mark', 'Gender']

rows=[
    [1, 'Alex', 'Four', 75, 'Male'],
    [2, 'Ravi', 'Three', 65, 'Male']
]

configure_treeview(tree, headers, rows)

Reload Treeview when the Data Source Changes 🔝

The reusable function begins by deleting existing items:

for item in tree.get_children():
    tree.delete(item)

It then assigns a new column list and inserts the new rows.

This means the same Treeview can first show:

id | name

and later be rebuilt as:

id | name | class | mark | gender

without creating another Treeview widget.

Dynamic Treeview Columns in Tkinter and Updating Data

Number of Visible Rows and Scrolling 🔝

The Treeview height option controls the approximate number of visible rows:

tree['height']=8

It does not limit how many items can be inserted.

For datasets containing more rows or columns, add scrollbars:

ys=ttk.Scrollbar(root, orient='vertical', command=tree.yview)
xs=ttk.Scrollbar(root, orient='horizontal', command=tree.xview)
tree.configure(yscrollcommand=ys.set, xscrollcommand=xs.set)

Complete Dynamic Treeview Example 🔝

This complete example uses a simple list as the data source. Replace the headers and rows section with any of the MySQL, SQLite, Pandas, Excel or CSV examples above.

import tkinter as tk
from tkinter import ttk

def configure_treeview(tree, headers, rows):
    for item in tree.get_children():
        tree.delete(item)

    column_ids=[f'col{i}' for i in range(len(headers))]
    tree['columns']=column_ids
    tree['show']='headings'

    for column_id, heading in zip(column_ids, headers):
        heading_text='' if heading is None else str(heading)
        tree.heading(column_id, text=heading_text)
        tree.column(column_id, width=110, minwidth=60, anchor='center')

    for row in rows:
        values=list(row)
        if len(values)<len(column_ids):
            values+=['']*(len(column_ids)-len(values))
        tree.insert('', tk.END, values=values[:len(column_ids)])

headers=['id', 'Name', 'Class', 'Mark', 'Gender']

rows=[
    (1, 'Alex', 'Four', 75, 'Male'),
    (2, 'Ravi', 'Three', 65, 'Male'),
    (3, 'Ron', 'Five', 80, 'Male')
]

root=tk.Tk()
root.geometry('700x350')
root.title('Dynamic Treeview - plus2net')

root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)

tree=ttk.Treeview(root, show='headings', selectmode='browse', height=8)
tree.grid(row=0, column=0, sticky='nsew', padx=(10, 0), pady=(10, 0))

ys=ttk.Scrollbar(root, orient='vertical', command=tree.yview)
ys.grid(row=0, column=1, sticky='ns', pady=(10, 0))

xs=ttk.Scrollbar(root, orient='horizontal', command=tree.xview)
xs.grid(row=1, column=0, sticky='ew', padx=(10, 0))

tree.configure(yscrollcommand=ys.set, xscrollcommand=xs.set)
configure_treeview(tree, headers, rows)

root.mainloop()

Dynamic Treeview for Reports 🔝

The same technique is useful when the user changes a filter and a new database query returns another set of rows.

For example, a Combobox can select a month, a SQL query can retrieve matching records, and the existing Treeview can be cleared and filled with the new result.

Tkinter Monthly Report using Treeview, Combobox and MySQL

See the related monthly Treeview report tutorial for the complete project.

Common Dynamic Treeview Mistakes 🔝

1. Assuming the Number of Columns Is Fixed

Use the source metadata or first row to build the column list instead.

2. Using Source Headings Directly as Treeview IDs

Duplicate or blank headings can cause problems. Use internal identifiers such as col0, col1 and col2.

3. Using the First Data Value as iid

The first value may be duplicated or empty. Let Treeview generate item IDs unless the source contains a reliable unique key.

4. Forgetting to Clear Existing Rows

Before displaying a replacement dataset:

for item in tree.get_children():
    tree.delete(item)

5. Assuming browse Means Scrollable

selectmode='browse' is a selection setting. Use Treeview scrollbars for scrolling.

6. Leaving Database Connections Open

Use a connection context manager:

with engine.connect() as conn:
    ...

7. Leaving CSV Files Open

Use:

with open('student.csv') as file:
    ...

8. Using Absolute Paths from One Computer

Avoid:

D:\student.xlsx
E:\testing\sqlite\my_db.db

Use project-relative paths where possible.

9. Loading Huge Datasets into Memory

The examples use lists because the sample student data is small. For very large data sources, use pagination, SQL limits or incremental loading rather than placing every record in one Treeview.

See Treeview pagination with MySQL for one approach.

Dynamic Treeview Summary 🔝

  • A Treeview can create its columns from data-source metadata.
  • Convert every source into a common headers + rows structure.
  • Use one reusable function to configure the Treeview.
  • Safe internal IDs such as col0 prevent duplicate-header problems.
  • Visible Treeview headings can still use the original source names.
  • Do not assume the first data field is always a valid unique iid.
  • MySQL and SQLite query results can provide headers through result.keys().
  • Pandas provides headings through df.columns.
  • OpenPyXL can use the first worksheet row as headings.
  • CSV can use its first row as headings.
  • The same Treeview can be cleared and rebuilt when the dataset changes.
  • height controls the visible row count, not the total number of records.
  • selectmode='browse' controls selection, not scrolling.
  • Use scrollbars for larger datasets.
  • Use pagination or limited queries for very large tables.
Search DataFrame from Tkinter MySQL Records in Treeview MySQL Treeview Pagination Query Window and Treeview

MySQL Records using Entry or Label Delete MySQL Record Edit and Update MySQL Product using Treeview




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer