Python Tkinter Treeview如何实现单列多值Excel式列筛选
Tkinter Treeview实现Excel式多值列筛选
Tkinter原生Treeview本身没有内置多值筛选功能,但完全可以基于原生控件扩展实现。你找到的单值筛选版本核心逻辑没问题,只需要替换单值选择控件、调整筛选判断规则即可支持同列多值勾选筛选,不需要依赖第三方库。
改造核心逻辑
- 替换原代码中每列的单选
ttk.Combobox为原生Menubutton搭配带复选框的下拉菜单,菜单内自动加载对应列的所有去重值,支持多选勾选 - 为每列单独维护一个存储已选筛选值的集合,替代原代码中单值存储的逻辑
- 调整放行判断规则:某列无选中值时不触发该列筛选;有选中值时,仅当行对应列的值在选中值集合内时才判定为符合条件
- 增加筛选状态提示:列设置筛选后自动在筛选按钮上显示标识,方便识别已筛选列
可直接运行的完整实现代码
from tkinter import * from tkinter import ttk # 测试数据 inp = [{'Currency': 'EUR', 'Volume': '100', 'Country': 'SE'}, {'Currency': 'GBR', 'Volume': '200', 'Country': 'SE'}, {'Currency': 'CAD', 'Volume': '300', 'Country': 'SE'}, {'Currency': 'EUR', 'Volume': '400', 'Country': 'SE'}, {'Currency': 'EUR', 'Volume': '100', 'Country': 'DK'}, {'Currency': 'GBR', 'Volume': '200', 'Country': 'DK'}, {'Currency': 'CAD', 'Volume': '300', 'Country': 'DK'}, {'Currency': 'EUR', 'Volume': '400', 'Country': 'DK'}, ] class ColumnFilter: def __init__(self, parent, col, tree, data, update_func): self.col = col self.tree = tree self.data = data self.update_func = update_func self.selected = set() # 获取列所有唯一值 self.unique_vals = sorted({str(row[col]) for row in data}) # 下拉多选菜单 self.menubtn = ttk.Menubutton(parent, text=f"{col} ▼") self.menu = Menu(self.menubtn, tearoff=0) self.menubtn.config(menu=self.menu) # 添加全选/清空选项 self.menu.add_command(label="全选", command=self.select_all) self.menu.add_command(label="清空筛选", command=self.clear_filter) self.menu.add_separator() # 添加每个值的复选框 self.val_vars = {} for val in self.unique_vals: var = BooleanVar(value=False) self.val_vars[val] = var self.menu.add_checkbutton(label=val, variable=var, command=self.on_select) def select_all(self): for val in self.val_vars: self.val_vars[val].set(True) self.on_select() def clear_filter(self): for val in self.val_vars: self.val_vars[val].set(False) self.on_select() def on_select(self): # 更新已选值集合 self.selected = {val for val, var in self.val_vars.items() if var.get()} # 更新按钮文本提示 if self.selected: self.menubtn.config(text=f"{self.col} 🔍") else: self.menubtn.config(text=f"{self.col} ▼") # 触发表格刷新 self.update_func() def match(self, row_val): # 无选中值直接放行 if not self.selected: return True return str(row_val) in self.selected class Application(Tk): def __init__(self): Tk.__init__(self) self.title("Volume") self.geometry("650x400") # 筛选栏容器 filter_frame = Frame(self) filter_frame.pack(expand=True, fill=X, padx=5, pady=5) self.tree = ttk.Treeview(self, show='headings') columns = list(inp[0].keys()) self.filters = {} # 初始化每列的筛选器 for col in columns: col_filter = ColumnFilter(filter_frame, col, self.tree, inp, self.refresh_table) col_filter.menubtn.pack(side=LEFT, expand=True, fill=X, padx=2) self.filters[col] = col_filter self.tree["columns"] = columns self.tree.pack(expand=TRUE, fill=BOTH, padx=5, pady=5) # 初始化列配置 for i in columns: self.tree.column(i, anchor="w", width=200) self.tree.heading(i, text=i, anchor="w") # 首次加载全量数据 self.refresh_table() def refresh_table(self): # 清空现有数据 for item in self.tree.get_children(): self.tree.delete(item) # 按筛选条件渲染行 for row in inp: match_all = True for col, col_filter in self.filters.items(): if not col_filter.match(row[col]): match_all = False break if match_all: self.tree.insert("", "end", values=list(row.values())) if __name__ == "__main__": root = Application() root.mainloop()
效果说明
运行后每列表头上方的按钮点击即可弹出多选菜单:
- 勾选多个值后,表格仅显示所有选中列值匹配的行
- 点击「全选」可快速选中当前列所有值,点击「清空筛选」可取消该列所有筛选条件
- 设置了筛选的列按钮会显示放大镜标识,和Excel的筛选提示逻辑一致
- 所有控件均为Tkinter原生组件,不需要额外安装依赖
内容的提问来源于stack exchange,提问作者Jace M
相关产品推荐
相关产品推荐

