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

如何在Tkinter网格布局中滚动多行文本框内容?

问题描述

我用Python的Tkinter写脚本,通过grid布局把Excel数据显示在窗口里,每个单元格对应一个Text组件。但数据多的时候看不全,这些Text都是动态生成的,不知道怎么加滚动功能。以下是生成文本框的代码片段:

# Extracting columns from the data and creating text widget with some background color
column_names = df.columns
i=0
for j, col in enumerate(column_names):
    text = Text(window, width=20, height=1, font=('Arial', 10,'bold'), bg = "#9BC2E6")
    text.grid(row=i,column=j, sticky="ew")
    text.tag_configure("tag_name", justify='center')
    text.insert(INSERT, col)
    text.tag_add("tag_name", "1.0", "end")

# adding all the other rows into the grid
for i in range(n_rows):
    for j in range(n_cols):
        text = Text(window, width=len(str(df.loc[i][j])), height=1, font=('Times', 8))
        text.grid(row=i+1,column=j, sticky="ew")
        text.tag_configure("tag_name", justify='center')
        text.insert(INSERT, df.loc[i][j])
        text.tag_add("tag_name", "1.0", "end")
        cells[(i,j)] = text
for i in range(n_rows):
    if i >= len(buttons_list):
        button = Button(window, text="Copiar", bg = "#08ec9c", command=lambda row=i: copy_row(cells, n_cols, row))
        button.grid(row=i+1,column=n_cols)
        buttons_list.append(button)
    else:
        buttons_list[i].grid(row=i+1,column=n_cols)
    
    if i >= len(remove_buttons_list):
        remove_button = Button(window, text="Remover", bg = "#ac4c1e", command=lambda row=i: remove_row(i))
        remove_button.grid(row=i+1,column=n_cols+1)
        remove_buttons_list.append(remove_button)
    else:
        remove_buttons_list[i].grid(row=i+1,column=n_cols + 1)


        all_data = [df.iloc[i].values.tolist() for i in range(n_rows)]
实现滚动功能的方案

Tkinter里给动态网格加滚动的核心思路是:把所有Text组件和按钮放到一个内部Frame里,再把这个Frame挂载到Canvas上,最后用Scrollbar控制Canvas的滚动。具体修改步骤如下:

1. 创建滚动所需的核心组件

先把原来直接放在主窗口的控件转移到专用容器里,同时创建滚动条和画布:

# 先清空主窗口原有控件(如果之前有其他控件)
for widget in window.winfo_children():
    widget.destroy()

# 创建垂直滚动条和画布
scrollbar = Scrollbar(window, orient="vertical")
canvas = Canvas(window, yscrollcommand=scrollbar.set)
scrollbar.config(command=canvas.yview)

# 创建承载所有控件的内部Frame
inner_frame = Frame(canvas)
# 监听Frame尺寸变化,自动更新画布的滚动范围
inner_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))

# 把内部Frame放到画布上
canvas.create_window((0, 0), window=inner_frame, anchor="nw")

# 布局滚动条和画布
scrollbar.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)

2. 修改原有代码,将控件挂载到内部Frame

把原来代码里所有控件的父组件(window)替换成inner_frame,也就是修改所有Text(...)和Button(...)的第一个参数,以及对应的grid调用:

修改表头部分:

column_names = df.columns
i=0
for j, col in enumerate(column_names):
    # 把window换成inner_frame
    text = Text(inner_frame, width=20, height=1, font=('Arial', 10,'bold'), bg = "#9BC2E6")
    text.grid(row=i,column=j, sticky="ew")
    text.tag_configure("tag_name", justify='center')
    text.insert(INSERT, col)
    text.tag_add("tag_name", "1.0", "end")

修改数据行部分:

for i in range(n_rows):
    for j in range(n_cols):
        # 把window换成inner_frame
        text = Text(inner_frame, width=len(str(df.loc[i][j])), height=1, font=('Times', 8))
        text.grid(row=i+1,column=j, sticky="ew")
        text.tag_configure("tag_name", justify='center')
        text.insert(INSERT, df.loc[i][j])
        text.tag_add("tag_name", "1.0", "end")
        cells[(i,j)] = text

修改按钮部分:

for i in range(n_rows):
    if i >= len(buttons_list):
        # 把window换成inner_frame
        button = Button(inner_frame, text="Copiar", bg = "#08ec9c", command=lambda row=i: copy_row(cells, n_cols, row))
        button.grid(row=i+1,column=n_cols)
        buttons_list.append(button)
    else:
        buttons_list[i].grid(row=i+1,column=n_cols)
    
    if i >= len(remove_buttons_list):
        # 把window换成inner_frame
        remove_button = Button(inner_frame, text="Remover", bg = "#ac4c1e", command=lambda row=i: remove_row(i))
        remove_button.grid(row=i+1,column=n_cols+1)
        remove_buttons_list.append(remove_button)
    else:
        remove_buttons_list[i].grid(row=i+1,column=n_cols + 1)

3. 可选优化:列宽自适应窗口

如果希望列能随窗口宽度自动拉伸,避免横向滚动,可以给内部Frame的列设置权重:

# 给所有列(包括按钮列)设置拉伸权重
for j in range(n_cols + 2):
    inner_frame.grid_columnconfigure(j, weight=1)

逻辑说明

  • 所有动态生成的控件都集中在inner_frame里,这个Frame会随着内容多少自动调整高度
  • Canvas会监听inner_frame的尺寸变化,实时更新可滚动范围
  • Scrollbar和Canvas绑定,拖动滚动条就能上下查看全部内容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:05:31