You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 00:06:34