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

在tkinter中使用grid布局时如何添加可正常工作的滚动条?

解决方案

Tkinter原生Scrollbar无法直接绑定普通Frame实现滚动,不管你用grid还是pack布局,都需要通过Canvas作为中间载体实现滚动容器,你原有grid布局的逻辑不需要改动,只需要套一层滚动容器结构即可。
核心修改点:

  • 在Create页面新增「外层容器Frame + Canvas + 滚动条 + 内容Frame」的四层滚动结构,你原有输入组件的grid布局逻辑全部迁移到内部内容Frame上,原有排列规则完全保留
  • 滚动条仅初始化一次,删除了每次点击新增按钮重复创建滚动条的冗余逻辑
  • 绑定了内容尺寸变化自动更新滚动区域、鼠标滚轮滚动的交互逻辑

修改后可直接运行的完整代码:

from tkinter import *
import tkinter as tk

class Insert(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        
        container = tk.Frame(self)
        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=1)
        container.pack(side="top", fill="both", expand=True)

        self.frameslist = {}

        for frame in (Create,):
            frame_occurrence = frame.__name__
            active_frame = frame(parent=container, controller=self)
            self.frameslist[frame_occurrence] = active_frame
            active_frame.grid(row=0, column=0, sticky="snew")

        self.show_frame("Create")
            
    def show_frame(self, frame_occurrence):
        active_frame = self.frameslist[frame_occurrence]
        active_frame.tkraise()

class Create(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        # -------------------------- 新增滚动容器结构开始 --------------------------
        # 外层容器,放Canvas和滚动条
        self.scroll_container = tk.Frame(self)
        self.scroll_container.pack(fill="both", expand=True)

        # 垂直滚动条
        self.v_scroll = tk.Scrollbar(self.scroll_container, orient=VERTICAL)
        self.v_scroll.pack(side=RIGHT, fill=Y)

        # Canvas载体,用来承载内容Frame
        self.canvas = tk.Canvas(self.scroll_container, yscrollcommand=self.v_scroll.set)
        self.canvas.pack(side=LEFT, fill="both", expand=True)

        self.v_scroll.config(command=self.canvas.yview)

        # 绑定鼠标滚轮滚动事件
        self.canvas.bind_all("<MouseWheel>", lambda e: self.canvas.yview_scroll(int(-1*(e.delta/120)), "units"))
        self.canvas.bind("<Configure>", lambda e: self.canvas.config(scrollregion=self.canvas.bbox("all")))

        # 内容Frame,你原来的所有组件都放在这个Frame里,原有grid逻辑不变
        self.content_frame = tk.Frame(self.canvas)
        self.canvas.create_window((0,0), window=self.content_frame, anchor="nw")

        # 内容Frame尺寸变化时更新滚动区域
        def update_scrollregion(event):
            self.canvas.config(scrollregion=self.canvas.bbox("all"))
        self.content_frame.bind("<Configure>", update_scrollregion)
        # -------------------------- 新增滚动容器结构结束 --------------------------

        #For all widgets (nested list, 2 widgets per row)
        self.inputlist = []
        #For just the entries
        self.newinputlist = []

        #Create two labels, add them into the inputlist to be iterated
        labels = [tk.Label(self.content_frame, text="Field"), tk.Label(self.content_frame, text="Values")]
        self.inputlist.append(labels[:])

        #Insert the labels from the list
        for toplabels in range(1):
            self.inputlist[toplabels][0].grid(row=toplabels, column=0, padx=10, pady=5)
            self.inputlist[toplabels][1].grid(row=toplabels, column=1, padx=10, pady=5)

        #Create the first two entry boxes, append them to the inputlist, and newinput list
        first_entries = [tk.Entry(self.content_frame, borderwidth=5), tk.Text(self.content_frame, borderwidth=5, height= 5, width=20)]
        self.newinputlist.append(first_entries[:])
        self.inputlist.append(first_entries[:])

        #Insert the entries from the newinputlist
        for x in range(0, len(self.newinputlist) + 1):
            self.newinputlist[0][x].grid(row=1, column=x, padx=10, pady=5)

        #Create two buttons (Both share same row), append them to list
        button_input_1 = [tk.Button(self.content_frame, text="ADD FIELD/VALUE", command=self.add_insert), tk.Button(self.content_frame, text="BACK")]
        self.inputlist.append(button_input_1[:])
        
        #Insert buttons at the bottom of the grid
        for button in range(len(self.inputlist) - 2, len(self.inputlist)):
            self.inputlist[button][0].grid(row=button, column=0, padx=10, pady=5)
            self.inputlist[button][1].grid(row=button, column=1, padx=10, pady=5)

    def add_insert(self):
        #Create two new entries, append them to the list
        add_input = [tk.Entry(self.content_frame, borderwidth=5), tk.Text(self.content_frame, borderwidth=5, height= 5, width=20)]
        self.inputlist.insert(-1, add_input)
        self.newinputlist.append(add_input)
        
        #Because there are new entry boxes, old grid should be forgotten
        for widget in self.content_frame.children.values():
            widget.grid_forget()

        #Use the index for the row, get all widgets and place them again
        for index, widgets in enumerate(self.inputlist):
            widget_one = widgets[0]
            widget_two = widgets[1]

            widget_one.grid(row=index, column=0, padx=10, pady=5)
            widget_two.grid(row=index, column=1, padx=10)

if __name__ == "__main__":
    app = Insert()
    app.maxsize(0, 500)
    app.mainloop()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 07:30:03