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

Tkinter Treeview设置列宽为0后残留黄色像素问题求助

问题:Treeview隐藏列后残留黄色像素

我通过点击右侧按钮切换视图,仅显示特定列,实现逻辑是将不需要的列宽度设为0来隐藏。虽然列已隐藏,但原位置残留黄色像素,视觉效果不佳,请问如何去除这些黄色像素?

代码说明

数据表格窗口:
    用户点击按钮(如"显示数据表格")时打开数据表格窗口。
    使用pd.read_excel加载Excel文件到Pandas DataFrame(df)中。

窗口配置:
    窗口配置为支持交互式显示带样式的DataFrame。
    创建ttk.Treeview组件来展示DataFrame的列。
    设置列标题和宽度。
    添加滚动条用于Treeview导航。

搜索功能:
    添加搜索输入框和搜索按钮,用于查找特定数据。
    用户按回车键或点击搜索按钮时调用search_data函数。

视图切换按钮:
    添加多个按钮(如"每日视图"、"订单视图"、"每周视图")来激活特定视图。
    调用对应的函数(show_tagesbasis、show_bestellbasis、show_wochenbasis)隐藏列并更新视图。

重置按钮:
    添加"重置"按钮,将视图恢复到初始状态。
    调用reset_view函数重新显示所有列并更新视图。

颜色编码(已注释):
    原本有单元格颜色编码逻辑,但已被注释掉。

相关代码

# 导入必要的库和模块
import tkinter as tk
from tkinter import ttk  # 导入主题tk模块
from tkcalendar import DateEntry  # 日历功能
from babel import numbers
import datetime  # 日期转换
import matplotlib
matplotlib.use("TkAgg")  # 使用Tkinter作为绘图后端
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt  # 绘图功能
import numpy as np  # 绘图功能
import matplotlib.dates as mdates  # 日期转换为星期
import locale  # X轴标签设为德语
from PIL import Image, ImageTk  # 图片功能
import pandas as pd  # 导入pandas读取Excel数据
from tkinter.ttk import Separator
import mplcursors  # 图表点鼠标悬停
import warnings  # 过滤图表鼠标悬停警告:"PolyCollection缺少拾取支持,且Selection.target.index属性已弃用。"
import time  # 启动屏幕进度条
import threading  # 启动屏幕进度条
from functools import partial  # 将进度条与DataFrame加载关联
from tkinter import messagebox  # 错误提示(如Excel数据为空)
import os

def on_datenblatt_button_click():
    print("函数启动")

    try:
        # 加载Excel文件
        file_path = 'data/Input.xlsx'
        df = pd.read_excel(file_path)

        # 检查窗口是否已打开
        if hasattr(on_datenblatt_button_click, 'styled_window') and on_datenblatt_button_click.styled_window.winfo_exists():
            # 若已打开则关闭窗口
            on_datenblatt_button_click.styled_window.destroy()
            return  # 退出函数避免重复打开

        # 数字保留两位小数
        df = df.round(2)

        # 创建新窗口用于交互式显示带样式的DataFrame
        styled_window = tk.Toplevel(start_window)
        styled_window.title("数据表格")

        # 将窗口保存为函数属性以便后续访问
        on_datenblatt_button_click.styled_window = styled_window

        # 窗口尺寸配置(居中显示)
        window_width = 1000
        window_height = 600
        styled_window.geometry(f'{window_width}x{window_height}')
        # screen_width = styled_window.winfo_screenwidth()
        # screen_height = styled_window.winfo_screenheight()
        # x_coordinate = int((screen_width - window_width) / 2)
        # y_coordinate = int((screen_height - window_height) / 2)
        # styled_window.geometry(f'{window_width}x{window_height}+{x_coordinate}+{y_coordinate}')

        # 创建带样式的ttk.Treeview组件
        style = ttk.Style()
        style.configure("Treeview", font=('Arial', 12))

        tree = ttk.Treeview(styled_window)
        tree["columns"] = list(df.columns)
        tree["show"] = "headings"  # 不显示左侧空列

        # 添加列标题
        col_width = 120
        # 设置所有列宽度
        for col in df.columns:
            tree.heading(col, text=col)
            tree.column(col, width=col_width, stretch=tk.NO)  # 设置stretch为tk.NO,宽度为col_width

        # 放置Treeview组件
        tree.pack(fill='both', side='left')

        # 添加滚动条
        scrollbar = ttk.Scrollbar(styled_window, orient='vertical', command=tree.yview)
        scrollbar.pack(side='right', fill='y')
        tree.configure(yscrollcommand=scrollbar.set)

        # 创建搜索框架
        search_frame = ttk.Frame(styled_window)
        search_frame.pack(side='top', fill='x')

        # 搜索输入框
        search_entry = ttk.Entry(search_frame)
        search_entry.grid(row=0, column=0, padx=5, pady=5)
        # 绑定回车键触发搜索
        search_entry.bind('<Return>', lambda event: search_data(tree, df, search_entry.get()))

        # 搜索按钮
        search_button = ttk.Button(search_frame, text="搜索", command=lambda: search_data(tree, df, search_entry.get()))
        search_button.grid(row=1, column=0, padx=5, pady=5)

        # 空白框架用于间距
        ttk.Frame(search_frame, height=10).grid(row=2, column=0)

        # 视图切换按钮
        tagesbasis_button = ttk.Button(search_frame, text="每日视图", command=lambda: show_tagesbasis(tree, df, styled_window))
        tagesbasis_button.grid(row=3, column=0, padx=5, pady=5)

        bestellbasis_button = ttk.Button(search_frame, text="订单视图", command=lambda: show_bestellbasis(tree, df, styled_window))
        bestellbasis_button.grid(row=4, column=0, padx=5, pady=5)

        wochenbasis_button = ttk.Button(search_frame, text="每周视图", command=lambda: show_wochenbasis(tree, df, styled_window))
        wochenbasis_button.grid(row=5, column=0, padx=5, pady=5)

        # 空白框架用于间距
        ttk.Frame(search_frame, height=10).grid(row=6, column=0)

        reset_button = ttk.Button(search_frame, text="重置", command=lambda: reset_view(tree, df))
        reset_button.grid(row=7, column=0, padx=5, pady=5)

        # # 设置单元格颜色
        # for tag in ['green', 'yellow', 'red']:
        #     tree.tag_configure(tag, background='')

        # 添加数据条目(无颜色)
        for index, row in df.iterrows():
            values = list(row)
            tree.insert("", tk.END, values=values, iid=index)

            # 保存最新日期和索引的选中状态
            if index == df.index[-1]:
                styled_window.selected_date = row['Date']
                styled_window.selected_index = index

        # 设置选中最新日期
        tree.selection_set(styled_window.selected_index)
        tree.see(styled_window.selected_index)

    except Exception as e:
        print(f"发生错误: {e}")

    print("函数结束")

def search_data(tree, df, search_date):
    try:
        # 将日期转为字符串后搜索
        matching_rows = df.index[df['Date'].astype(str).str.contains(search_date, case=False, na=False)].tolist()
        if matching_rows:
            tree.selection_set(matching_rows[0])
            tree.see(matching_rows[0])
    except Exception as e:
        print(f"搜索时发生错误: {e}")

# def color_by_deviation(prognose_value, ist_value):
#     color = 'green' if ist_value == 0 or prognose_value == 0 else (
#         'green' if abs(ist_value - prognose_value) / ist_value <= 0.1 else (
#             'yellow' if abs(ist_value - prognose_value) / ist_value <= 0.3 else 'red'
#         )
#     )
#     return color

def show_tagesbasis(tree, df, styled_window):
    reset_view(tree, df)
    hide_column(tree, df, styled_window, '(Actual) Order', 'Forecast Order', '(Actual) Week', 'Forecast Week')

def show_bestellbasis(tree, df, styled_window):
    reset_view(tree, df)
    hide_column(tree, df, styled_window, '(Actual) Sales', 'Forecast Sales', '(Actual) Week', 'Forecast Week')

def show_wochenbasis(tree, df, styled_window):
    reset_view(tree, df)
    hide_column(tree, df, styled_window, '(Actual) Sales', 'Forecast Sales', '(Actual) Order', 'Forecast Order')

def reset_view(tree, df):
    show_all_columns(tree, df)
    # reset_colors(tree)
    update_entries(tree, df)

def hide_column(tree, df, styled_window, *columns_to_hide):
    for col in columns_to_hide:
        # 隐藏列
        tree.column(col, width=0, stretch=tk.NO)

    # 更新Treeview组件
    styled_window.update_idletasks()

def update_entries(tree, df):
    for index, row in df.iterrows():
        values = list(row)
        tree.item(index, values=values)

def show_all_columns(tree, df):
    for col in df.columns:
        tree.column(col, width=120, stretch=tk.NO)

解决方案

1. 彻底移除列而非仅设置宽度为0

ttk.Treeview设置宽度为0时,可能仍会渲染列的边框或残留样式缓存,直接移除不需要的列能从根源解决这个问题。修改核心函数如下:

def hide_column(tree, df, styled_window, *columns_to_hide):
    # 获取需要保留的列
    visible_columns = [col for col in df.columns if col not in columns_to_hide]
    # 更新Treeview的列配置
    tree["columns"] = visible_columns
    # 重新设置表头和列宽度
    for col in visible_columns:
        tree.heading(col, text=col)
        tree.column(col, width=120, stretch=tk.NO)
    # 清空现有条目并重新插入仅包含可见列的数据
    for item in tree.get_children():
        tree.delete(item)
    for index, row in df.iterrows():
        # 只保留可见列的值
        values = [row[col] for col in visible_columns]
        tree.insert("", tk.END, values=values, iid=index)
    # 恢复选中状态
    if hasattr(styled_window, 'selected_index') and styled_window.selected_index in df.index:
        tree.selection_set(styled_window.selected_index)
        tree.see(styled_window.selected_index)
    styled_window.update()
    tree.update()

def show_all_columns(tree, df):
    # 恢复所有列
    tree["columns"] = list(df.columns)
    for col in df.columns:
        tree.heading(col, text=col)
        tree.column(col, width=120, stretch=tk.NO)
    # 重新插入所有数据
    for item in tree.get_children():
        tree.delete(item)
    for index, row in df.iterrows():
        values = list(row)
        tree.insert("", tk.END, values=values, iid=index)
    # 恢复选中状态
    if hasattr(tree.master, 'selected_index'):
        tree.selection_set(tree.master.selected_index)
        tree.see(tree.master.selected_index)
    tree.master.update()
    tree.update()

2. 清除样式缓存

残留的黄色像素可能来自Treeview的选中样式或旧的tag配置,即使注释了颜色代码,仍可强制清除所有item的tag。在reset_view函数中添加:

# 清除所有条目的tag
for item in tree.get_children():
    tree.item(item, tags=())

3. 优化视图切换逻辑

将原reset_view函数修改为:

def reset_view(tree, df):
    show_all_columns(tree, df)
    # 清除所有条目的tag
    for item in tree.get_children():
        tree.item(item, tags=())
    # 恢复选中状态
    if hasattr(tree.master, 'selected_index'):
        tree.selection_set(tree.master.selected_index)
        tree.see(tree.master.selected_index)

内容的提问来源于stack exchange,提问作者Sld335

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:17:02