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

Tkinter Notebook仅显示数据表顶部内容的问题求助

Tkinter Notebook 数据表内容被截断问题修复方案

开发用于展示数据表的Tkinter Notebook组件时,出现数据表仅显示顶部部分的问题。尝试调整标签页框架及Notebook高度参数、切换pack/grid布局均未解决。以下是问题代码及效果截图:

问题代码

import tkinter as tk
from tkinter import ttk, messagebox
import os

# 假设LEMS_EnergyCalcs是已实现的业务函数
def LEMS_EnergyCalcs(folder, output_path, log_path):
    return ("trail", {"test_weighted": "unit"}, {"test_weighted": 123.456}, "logs")

class LEMSDataCruncher_L2(tk.Frame):
    def __init__(self, root):
        tk.Frame.__init__(self, root)

        # 垂直滚动条
        self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff")
        self.main_frame = tk.Frame(self.canvas, background="#ffffff")
        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)
        self.vsb.pack(side="right", fill="y")

        # 水平滚动条
        self.hsb = tk.Scrollbar(self, orient="horizontal", command=self.canvas.xview)
        self.canvas.configure(xscrollcommand=self.hsb.set)
        self.hsb.pack(side="bottom", fill="x")

        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas.create_window((8, 8), window=self.main_frame, anchor="nw", tags="main_frame")

        self.main_frame.bind("<Configure>", self.onFrameConfigure)
        # 给主容器设置grid权重,确保空间能扩展
        self.main_frame.grid_rowconfigure(0, weight=1)
        self.main_frame.grid_columnconfigure(0, weight=1)

        # 文件路径输入区
        tk.Label(self.main_frame, text="Select Folder:").grid(row=0, column=0)
        self.folder_path_var = tk.StringVar()
        self.folder_path = tk.Entry(self.main_frame, textvariable=self.folder_path_var, width=150)
        self.folder_path.grid(row=0, column=0)

        self.energy_files = [os.path.join(os.getcwd(), "EnergyInputs.csv")] # 模拟测试路径

        # 浏览按钮
        browse_button = tk.Button(self.main_frame, text="Browse", command=self.on_browse)
        browse_button.grid(row=0, column=1)

        # OK按钮
        ok_button = tk.Button(self.main_frame, text="OK", command=self.on_okay)
        ok_button.grid(row=1, column=0, pady=10)

        # 鼠标滚轮绑定
        self.canvas.bind_all("<MouseWheel>", self.onCanvasMouseWheel)

        self.pack(side=tk.TOP, fill="both", expand=True)

    def onFrameConfigure(self, event):
        # 关键缺失方法:更新画布滚动区域
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def onCanvasMouseWheel(self, event):
        if event.delta > 0:
            self.canvas.yview_scroll(-1, "units")
        elif event.delta < 0:
            self.canvas.yview_scroll(1, "units")

    def on_browse(self):
        # 实现文件夹选择逻辑(省略)
        pass

    def on_okay(self):
        error = []
        # 创建Notebook容器
        self.notebook = ttk.Notebook(self.main_frame)
        # 让Notebook占满可用空间
        self.notebook.grid(row=2, column=0, sticky="nsew", columnspan=2)
        self.main_frame.grid_rowconfigure(2, weight=1)

        for folder in self.energy_files:
            try:
                output_path = folder.replace('EnergyInputs.csv', 'EnergyOutputs.csv')
                log_path = folder.replace('EnergyInputs.csv', 'log.txt')
                [trail, units, data, logs] = LEMS_EnergyCalcs(folder, output_path, log_path)

                # 创建标签页框架
                tab_frame = tk.Frame(self.notebook)
                tab_frame.grid_rowconfigure(0, weight=1)
                tab_frame.grid_columnconfigure(0, weight=1)
                tab_frame.grid(row=0, column=0, sticky="nsew")

                # 创建标签页内部容器,避免覆盖主frame变量
                tab_inner_frame = tk.Frame(tab_frame, background="#ffffff")
                tab_inner_frame.grid(row=0, column=0, sticky="nsew")
                tab_inner_frame.grid_rowconfigure(0, weight=1)
                tab_inner_frame.grid_columnconfigure(0, weight=1)

                # 数据保留三位小数
                round_data = {}
                for name in data:
                    try:
                        rounded = round(data[name], 3)
                    except:
                        rounded = data[name]
                    round_data[name] = rounded

                data = round_data

                # 生成输出表格
                self.create_output_table(data, units, logs, num_columns=150,
                                         num_rows=300,
                                         folder_path=folder, parent_frame=tab_inner_frame)

                # 添加标签页
                self.notebook.add(tab_frame, text=os.path.basename(os.path.dirname(folder)))

            except PermissionError:
                error.append(folder)

        if error:
            message = f"One or more files are open in another program. Close them and try again."
            messagebox.showerror("Error", message)

        self.notebook.bind("<ButtonRelease-1>", lambda event: self.canvas.yview_moveto(0))

    def create_output_table(self, data, units, logs, num_columns, num_rows, folder_path, parent_frame):
        # 清空容器原有控件
        for widget in parent_frame.winfo_children():
            widget.destroy()

        # 创建表格组件
        output_table = OutputTable(parent_frame, data, units, logs, num_columns, num_rows, folder_path)
        output_table.grid(row=0, column=0, sticky="nsew")

class OutputTable(tk.Frame):
    def __init__(self, root, data, units, logs, num_columns, num_rows, folder_path):
        tk.Frame.__init__(self, root)
        # 设置自身布局权重
        self.grid_rowconfigure(1, weight=1)
        self.grid_rowconfigure(3, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(3, weight=1)

        # 退出按钮
        exit_button = tk.Button(self, text="EXIT", command=root.quit, bg="red", fg="white")
        exit_button.grid(row=0, column=4, padx=(350, 5), pady=5, sticky="e")

        # 查找输入框
        self.find_entry = tk.Entry(self, width=100)
        self.find_entry.grid(row=0, column=0, padx=0, pady=0, columnspan=3)

        find_button = tk.Button(self, text="Find", command=self.find_text)
        find_button.grid(row=0, column=3, padx=0, pady=0)

        # 修复缺失的text_widget
        self.text_widget = tk.Text(self, wrap="none", height=num_rows, width=110)
        self.text_widget.tag_configure("bold", font=("Helvetica", 12, "bold"))
        self.text_widget.grid(row=1, column=0, padx=0, pady=10, columnspan=4, sticky="nsew")

        # 主表格标题
        header = "{:<110}|".format("ALL ENERGY OUTPUTS")
        self.text_widget.insert(tk.END, header + "\n" + "_" * 63 + "\n", "bold")
        header = "{:<64} | {:<31} | {:<18} |".format("Variable", "Value", "Units")
        self.text_widget.insert(tk.END, header + "\n" + "_" * 63 + "\n", "bold")

        # 加权指标表格
        self.cut_table = tk.Text(self, wrap="none", height=num_rows, width=72)
        self.cut_table.tag_configure("bold", font=("Helvetica", 12, "bold"))
        self.cut_table.grid(row=3, column=0, padx=0, pady=10, columnspan=4, sticky="nsew")

        cut_header = "{:<113}|".format("WEIGHTED METRICS")
        self.cut_table.insert(tk.END, cut_header + "\n" + "_" * 63 + "\n", "bold")
        cut_header = "{:<64} | {:<31} | {:<18} |".format("Variable", "Value", "Units")
        self.cut_table.insert(tk.END, cut_header + "\n" + "_" * 63 + "\n", "bold")

        # 填充加权指标数据
        for key, value in data.items():
            unit = units.get(key, "")
            val = value if value else " "
            unit = unit if unit else " "
            if key.endswith('weighted'):
                row = "{:<35} | {:<17} | {:<10} |".format(key, val, unit)
                self.cut_table.insert(tk.END, row + "\n")
                self.cut_table.insert(tk.END, "_" * 70 + "\n")

    def find_text(self):
        # 实现查找逻辑(省略)
        pass

if __name__ == "__main__":
    root = tk.Tk()
    root.geometry("1200x800")
    app = LEMSDataCruncher_L2(root)
    root.mainloop()

原问题效果截图

数据表截断效果

核心修复点

  • 补全滚动区域更新方法:添加onFrameConfigure方法,让画布能感知内容变化并更新滚动范围。
  • 避免变量覆盖:原代码中用self.frame重写主容器变量,导致滚动绑定失效,改用独立变量存储标签页内容器。
  • 配置布局权重:所有容器通过grid_rowconfigure和grid_columnconfigure设置weight=1,并添加sticky="nsew"确保控件随父容器扩展。
  • 修复缺失控件:补充OutputTable中未创建的self.text_widget,并正确设置其布局属性。
  • 调整Notebook布局:将Notebook放在独立行并设置权重,确保它能占据剩余显示空间。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 16:37:02