We can read rows from an Excel worksheet with OpenPyXL and display the data in a Tkinter Treeview. The Excel header row can be used as the visible Treeview headings, while each following worksheet row becomes one Treeview item.
This approach is useful when the number or names of Excel columns are not known in advance because the Treeview columns can be created dynamically from the worksheet.
Install OpenPyXL if it is not already available:
pip install openpyxl
The sample workbook contains a worksheet named student.
from openpyxl import load_workbook
wb=load_workbook('student.xlsx', read_only=True, data_only=True)
ws=wb['student']
Using a relative filename makes the example portable. Place student.xlsx in the same directory as the Python script, or provide the correct relative path.
iter_rows() can return the cell values directly by using values_only=True.
headers=next(ws.iter_rows(min_row=1, max_row=1, values_only=True))
print(headers)
Sample output:
('id', 'name', 'class', 'mark', 'gender')
rows=list(ws.iter_rows(min_row=2, values_only=True))
Each item in rows is a tuple representing one Excel row.
iter_rows() returns OpenPyXL Cell objects. Treeview normally needs the actual cell values.import tkinter as tk
from tkinter import ttk
root=tk.Tk()
root.geometry('650x320')
root.title('Excel Data in Treeview - plus2net')
tree=ttk.Treeview(root, show='headings', selectmode='browse', height=8)
Because this example displays spreadsheet-style data rather than parent-child hierarchy, show='headings' is appropriate.
Excel headings should be used as the text displayed to the user. However, blank or duplicate Excel headings can cause problems when used directly as Treeview column identifiers.
Create safe internal column IDs instead:
column_ids=[f'col{i}' for i in range(len(headers))]
tree['columns']=column_ids
Then display the actual Excel headings:
for column_id, heading in zip(column_ids, headers):
heading_text=str(heading) if heading is not None else ''
tree.heading(column_id, text=heading_text)
tree.column(column_id, width=110, anchor='center')
col1, col2, etc. identify the Treeview columns internally. The original Excel header text is what the user sees.for row in rows:
tree.insert('', tk.END, values=row)
Treeview automatically generates an item ID for every row.
This is safer than:
tree.insert('', tk.END, iid=row[0], values=row)
unless the first Excel column is guaranteed to contain a unique, non-empty value for every record.
Excel files can contain more rows or columns than the application window can display.
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)
import tkinter as tk
from tkinter import ttk
from openpyxl import load_workbook
wb=load_workbook('student.xlsx', read_only=True, data_only=True)
ws=wb['student']
headers=next(ws.iter_rows(min_row=1, max_row=1, values_only=True))
rows=list(ws.iter_rows(min_row=2, values_only=True))
wb.close()
root=tk.Tk()
root.geometry('700x330')
root.title('Excel Data in Treeview - plus2net')
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
tree=ttk.Treeview(root, show='headings', selectmode='browse')
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)
column_ids=[f'col{i}' for i in range(len(headers))]
tree['columns']=column_ids
for column_id, heading in zip(column_ids, headers):
heading_text=str(heading) if heading is not None else ''
tree.heading(column_id, text=heading_text)
tree.column(column_id, width=110, minwidth=60, anchor='center')
for row in rows:
tree.insert('', tk.END, values=row)
root.mainloop()
iter_rows() supports limits for rows and columns.
rows=ws.iter_rows(min_row=2, max_row=20, min_col=1, max_col=5, values_only=True)
| Parameter | Purpose |
|---|---|
min_row | First worksheet row to read. |
max_row | Last worksheet row to read. |
min_col | First worksheet column to read. |
max_col | Last worksheet column to read. |
values_only | Return cell values instead of Cell objects. |
When loading a workbook with:
wb=load_workbook('student.xlsx', data_only=True)
cells containing formulas return the cached result stored in the Excel file, when one is available.
If data_only=False, the formula expression itself is returned instead.
Avoid:
D:\student.xlsx
when the workbook can be placed with the program:
student.xlsx
Blank or duplicate headings can create confusing Treeview definitions. Use internal IDs such as:
col0
col1
col2
and use the Excel values only as visible heading text.
This can fail when the value is duplicated or missing. Let Treeview create its own item IDs unless the worksheet contains a guaranteed unique key.
Without it, iter_rows() returns Cell objects rather than their values.
wb.close()
is especially relevant when a workbook is opened in read-only mode.
The simple tutorial uses:
rows=list(ws.iter_rows(...))
which is convenient for a small sample workbook. For a very large worksheet, process rows directly from the iterator instead of first copying every row into a Python list.
.xlsx workbooks.load_workbook() opens the Excel file.read_only=True is useful when only reading workbook content.iter_rows() reads worksheet rows.values_only=True returns cell values.values=.show='headings' is appropriate for spreadsheet-style tables.data_only=True can return cached formula results.Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.