目录
-
第一部分:基础入门
(图片来源网络,侵删)- 1 创建一个简单的 Treeview
- 2 添加列
- 3 插入数据项
- 4 运行第一个完整示例
-
第二部分:数据操作
- 1 添加父节点和子节点
- 2 更新和删除数据
- 3 获取数据
-
第三部分:交互与事件
- 1 绑定鼠标点击事件
- 2 处理选择变化事件 (
<<TreeviewSelect>>) - 3 实现双击展开/折叠功能
-
第四部分:高级用法
- 1 使用
Treeview作为表格 - 2 自定义行样式
- 3 添加滚动条
- 4 搜索功能
- 1 使用
-
第五部分:完整实战示例
(图片来源网络,侵删)1 一个简单的文件浏览器
基础入门
1 创建一个简单的 Treeview
你需要导入 tkinter 和 ttk 模块。ttk 模块提供了主题化的小部件,Treeview 就在其中。
import tkinter as tk
from tkinter import ttk
# 创建主窗口
root = tk.Tk()"Treeview 基础示例")
root.geometry("300x200")
# 创建 Treeview 组件
# 第一个参数是父窗口
tree = ttk.Treeview(root)
# 将 Treeview 放入主窗口
tree.pack(fill=tk.BOTH, expand=True)
# 启动主事件循环
root.mainloop()
这段代码会创建一个最简单的空树形视图。
2 添加列
默认情况下,Treeview 只有一列(通常称为 "#0"),用于显示树状结构,我们可以添加更多的列来显示其他信息。

# 添加两列,分别命名为 "姓名" 和 "年龄"
tree["columns"] = ("name", "age")
# 设置列的标题
tree.heading("#0", text="ID")
tree.heading("name", text="姓名")
tree.heading("age", text="年龄")
# 设置列的宽度
tree.column("#0", width=100, anchor=tk.CENTER) # anchor=tk.CENTER 让文字居中
tree.column("name", width=100, anchor=tk.CENTER)
tree.column("age", width=100, anchor=tk.CENTER)
3 插入数据项
使用 insert() 方法来添加数据。
parent: 父节点的 ID,如果是根节点,则为空字符串 。index: 插入的位置,可以是'end'(末尾),'0'(开头), 或一个数字。text: "#0" 列显示的文本。values: 一个元组,包含其他列的值。
# 插入根节点
tree.insert("", "end", text="用户组1", values=("Group 1", ""))
# 插入子节点
# parent 参数是父节点的 ID,这里我们使用 text 属性作为简单标识
# 在实际应用中,最好使用返回的 ID
child_id = tree.insert("", "end", text="用户A", values=("Alice", 25))
tree.insert("", "end", text="用户B", values=("Bob", 30))
# 插入另一个根节点
tree.insert("", "end", text="用户组2", values=("Group 2", ""))
tree.insert("", "end", text="用户C", values=("Charlie", 35))
4 运行第一个完整示例
将以上代码片段组合起来,你将看到一个功能完整的树形视图。
import tkinter as tk
from tkinter import ttk
# --- 创建主窗口 ---
root = tk.Tk()"我的第一个 Treeview")
root.geometry("400x300")
# --- 创建 Treeview ---
tree = ttk.Treeview(root, columns=("name", "age"), show="headings") # show="headings" 隐藏默认的 #0 列
# --- 配置列 ---
tree.heading("#0", text="ID")
tree.heading("name", text="姓名")
tree.heading("age", text="年龄")
tree.column("#0", width=100, anchor=tk.W) # anchor=tk.W 让文字左对齐
tree.column("name", width=150, anchor=tk.W)
tree.column("age", width=80, anchor=tk.CENTER)
# --- 插入数据 ---
# 插入一个顶级节点
group1 = tree.insert("", "end", text="组别 A", values=("Group A", ""))
# 在顶级节点下插入子节点
tree.insert(group1, "end", text="成员 1", values=("张三", 28))
tree.insert(group1, "end", text="成员 2", values=("李四", 32))
# 插入另一个顶级节点
group2 = tree.insert("", "end", text="组别 B", values=("Group B", ""))
tree.insert(group2, "end", text="成员 3", values=("王五", 45))
# --- 滚动条 ---超出窗口大小时可以滚动,我们需要添加一个滚动条
scrollbar = ttk.Scrollbar(root, orient="vertical", command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side='right', fill='y')
# --- 布局 ---
tree.pack(fill=tk.BOTH, expand=True)
# --- 启动主循环 ---
root.mainloop()
注意: show="headings" 会隐藏默认的 #0 列,只显示我们定义的列,如果不使用这个参数,则会同时显示 #0 列和我们定义的列。
数据操作
1 添加父节点和子节点
如上例所示,通过设置 parent 参数来创建层级关系。parent 参数是父节点的唯一标识符(ID),当你使用 insert() 时,它会返回该节点的 ID,这个 ID 可以用于后续操作。
# 获取父节点的 ID
parent_id = tree.insert("", "end", text="父节点", values=("Parent", "N/A"))
# 使用父节点的 ID 添加子节点
child_id = tree.insert(parent_id, "end", text="子节点", values=("Child", "N/A"))
# 可以继续添加孙子节点
grandchild_id = tree.insert(child_id, "end", text="孙子节点", values=("Grandchild", "N/A"))
2 更新和删除数据
- 更新:
item(item_id, **options)text: 更新 "#0" 列的文本。values: 更新其他列的值。
# 假设 child_id 是我们之前获取的子节点ID
tree.item(child_id, text="更新后的子节点", values=("Updated Child", "New Value"))
- 删除:
delete(item_id)删除指定节点及其所有子节点。
# 删除 "子节点" 及其所有后代 tree.delete(child_id)
- 清空整个树:
delete(*tree.get_children())get_children()获取所有顶级节点的 ID。
tree.delete(*tree.get_children())
3 获取数据
- 获取选中项的 ID:
selection()返回一个包含所有选中项 ID 的元组,如果没有选中项,返回空元组。
selected_ids = tree.selection()
if selected_ids:
print("选中的ID:", selected_ids)
# 通常我们只关心第一个选中的项
selected_id = selected_ids[0]
print("第一个选中项的ID:", selected_id)
- 获取节点的详细信息:
item(item_id)- 返回一个包含节点信息的字典,包括
text,image,values等。
- 返回一个包含节点信息的字典,包括
if selected_id:
node_info = tree.item(selected_id)
print("节点信息:", node_info)
# 获取 values
values = node_info['values']
print("节点的值:", values)
- 获取节点的文本:
item(item_id)['text']
交互与事件
Treeview 支持多种事件,让程序能够响应用户的操作。
1 绑定鼠标点击事件
<<TreeviewSelect>> 事件在用户选择或取消选择一个或多个节点时触发。
def on_select(event):
"""处理节点选择事件"""
selected_items = tree.selection()
print(f"当前选中的节点ID: {selected_items}")
for item_id in selected_items:
item_data = tree.item(item_id)
print(f" - ID: {item_id}, Text: {item_data['text']}, Values: {item_data['values']}")
# 绑定选择事件到 on_select 函数
tree.bind("<<TreeviewSelect>>", on_select)
2 处理选择变化事件
上面的 <<TreeviewSelect>> 已经是最常用的选择事件,这里再展示一个双击事件的例子。
3 实现双击展开/折叠功能
<<TreeviewOpen>> 和 <<TreeviewClose>> 事件在节点被展开或折叠时触发,我们可以通过绑定双击事件来实现手动切换。
def on_double_click(event):
"""处理双击事件,切换节点的展开/折叠状态"""
# 获取点击位置的项
item_id = tree.identify('item', event.x, event.y)
if item_id:
# 如果节点有子节点,则切换其展开状态
if tree.item(item_id)['children']:
tree.item(item_id, open=not tree.item(item_id)['open'])
# 绑定双击事件
tree.bind("<Double-1>", on_double_click) # <Double-1> 是鼠标左键双击
高级用法
1 使用 Treeview 作为表格
如果你不需要树状结构,只想用它来显示表格数据,可以这样做:
- 隐藏树列: 使用
show="tree"或show="headings"。 - 不设置
text: 在insert时,不提供text参数。
# 创建一个表格视图
table_tree = ttk.Treeview(root, columns=("Name", "Score", "Grade"), show="headings")
table_tree.heading("Name", text="姓名")
table_tree.heading("Score", text="分数")
table_tree.heading("Grade", text="等级")
# 插入数据(不提供 text)
table_tree.insert("", "end", values=("赵六", 95, "A"))
table_tree.insert("", "end", values=("钱七", 88, "B"))
table_tree.insert("", "end", values=("孙八", 76, "C"))
table_tree.pack(fill=tk.BOTH, expand=True)
2 自定义行样式
你可以为不同的行设置不同的背景色,以增强可读性。
- 定义样式: 使用
ttk.Style()。 - 应用样式: 在
insert时,使用tags参数。
# 创建样式对象
style = ttk.Style(root)
# 定义一个名为 'odd_row' 的样式
style.configure("odd_row", background="#E8E8E8")
# 定义一个名为 'even_row' 的样式
style.configure("even_row", background="#F0F0F0")
# 插入数据并应用标签
for i in range(10):
# 使用模运算判断奇偶行
tag = "odd_row" if i % 2 == 0 else "even_row"
tree.insert("", "end", text=f"项目 {i}", values=(f"Data {i}", i), tags=(tag,))
# 配置 Treeview 以使用这些标签
# 这一步很重要,告诉 Treeview 如何处理这些标签
tree.tag_configure("odd_row", background="#E8E8E8")
tree.tag_configure("even_row", background="#F0F0F0")
3 添加滚动条
这是一个非常常见的需求。Treeview 本身不包含滚动条,需要手动创建并关联。
# 创建 Treeview 和 Scrollbar tree = ttk.Treeview(root) scrollbar = ttk.Scrollbar(root, orient="vertical", command=tree.yview) # 将滚动条的命令绑定到 Treeview 的 yview tree.configure(yscrollcommand=scrollbar.set) # 使用 Frame 来布局,或者 pack/grid 两者 tree.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y")
4 搜索功能
实现一个搜索框,用于高亮或定位包含特定文本的节点。
def search_item():
search_term = entry.get()
# 先清除所有高亮
tree.tag_remove("highlight", "0", "end")
if not search_term:
return
# 遍历所有节点
for item_id in tree.get_children():
# 检查节点的 text 和 values 是否包含搜索词
item_text = tree.item(item_id)['text'].lower()
item_values = ' '.join(tree.item(item_id)['values']).lower()
if search_term.lower() in item_text or search_term.lower() in item_values:
# 如果找到,则高亮该节点
tree.selection_set(item_id) # 选中该节点
tree.see(item_id) # 确保该节点可见
tree.tag_add("highlight", item_id) # 添加高亮标签
break # 找到第一个后停止
# 定义高亮样式
style = ttk.Style(root)
style.configure("highlight", background="yellow")
# 创建搜索框和按钮
entry = ttk.Entry(root)
entry.pack(side="top", fill="x", padx=5, pady=5)
search_button = ttk.Button(root, text="搜索", command=search_item)
search_button.pack(side="top", padx=5)
# 创建 Treeview
tree = ttk.Treeview(root, columns=("value1",), show="tree headings")
tree.heading("#0", text="名称")
tree.heading("value1", text="值")
tree.pack(fill="both", expand=True)
# 插入一些测试数据
tree.insert("", "end", text="文件夹 A", values=("内容 A1",))
tree.insert("文件夹 A", "end", text="文件 A-1.txt", values=("数据 A-1",))
tree.insert("文件夹 A", "end", text="文件 A-2.txt", values=("数据 A-2",))
tree.insert("", "end", text="文件夹 B", values=("内容 B1",))
tree.insert("文件夹 B", "end", text="文件 B-1.txt", values=("数据 B-1",))
完整实战示例:一个简单的文件浏览器
这个示例将结合前面学到的知识,创建一个可以浏览本地文件系统目录的简单应用。
import tkinter as tk
from tkinter import ttk
import os
class FileBrowser(tk.Tk):
def __init__(self):
super().__init__()
self.title("Python 文件浏览器")
self.geometry("600x400")
# --- 布局 ---
self.tree_frame = ttk.Frame(self)
self.tree_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# --- 创建 Treeview 和滚动条 ---
self.tree = ttk.Treeview(self.tree_frame, columns=("size",), show="tree headings")
self.tree.heading("#0", text="文件/文件夹")
self.tree.heading("size", text="大小 (字节)")
self.tree.column("#0", width=400)
self.tree.column("size", width=150, anchor=tk.E)
scrollbar = ttk.Scrollbar(self.tree_frame, orient="vertical", command=self.tree.yview)
self.tree.configure(yscrollcommand=scrollbar.set)
self.tree.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# --- 绑定事件 ---
self.tree.bind("<<TreeviewSelect>>", self.on_item_select)
self.tree.bind("<Double-1>", self.on_double_click)
# --- 初始加载 ---
self.load_directory(os.path.expanduser("~")) # 加载用户主目录
def load_directory(self, path):
"""加载指定路径下的内容到 Treeview"""
# 清空当前 Treeview
self.tree.delete(*self.tree.get_children())
try:
# 获取目录内容
items = os.listdir(path)
for item in items:
full_path = os.path.join(path, item)
# 获取文件大小
size = os.path.getsize(full_path) if os.path.isfile(full_path) else ""
# 插入节点
node_id = self.tree.insert("", "end", text=item, values=(size,))
# 如果是目录,递归加载其内容
if os.path.isdir(full_path):
self.load_directory_recursive(full_path, node_id)
except PermissionError:
self.tree.insert("", "end", text="[无权限访问]", values=("",))
def load_directory_recursive(self, path, parent_id):
"""递归加载目录内容"""
try:
items = os.listdir(path)
for item in items:
full_path = os.path.join(path, item)
size = os.path.getsize(full_path) if os.path.isfile(full_path) else ""
node_id = self.tree.insert(parent_id, "end", text=item, values=(size,))
if os.path.isdir(full_path):
self.load_directory_recursive(full_path, node_id)
except PermissionError:
self.tree.insert(parent_id, "end", text="[无权限访问]", values=(""))
def on_item_select(self, event):
"""处理选择事件,在状态栏显示路径"""
selected_id = self.tree.selection()
if selected_id:
item_text = self.tree.item(selected_id[0])['text']
print(f"已选择: {item_text}")
def on_double_click(self, event):
"""处理双击事件,如果是目录则展开/折叠,如果是文件则可以打开(这里只打印)"""
item_id = self.tree.identify('item', event.x, event.y)
if not item_id:
return
item_text = self.tree.item(item_id)['text']
# 注意:这里我们没有存储完整的路径,这是一个简化的例子
# 一个更健壮的实现会存储完整路径在 item 的字典中
print(f"双击了: {item_text}")
# 如果是目录,切换展开状态
if self.tree.item(item_id)['children']:
self.tree.item(item_id, open=not self.tree.item(item_id)['open'])
if __name__ == "__main__":
app = FileBrowser()
app.mainloop()
tkinter.ttk.Treeview 是一个非常灵活和强大的组件,通过掌握其核心方法(insert, item, delete)和事件(<<TreeviewSelect>>),你可以创建出各种复杂的树形和表格界面,希望这份详细的教程能帮助你快速上手并应用到自己的项目中。
