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

Tkinter中Scrollbar与Grid布局关联失效问题求助

解决Tkinter滚动条无法控制角色列表区域的问题

你遇到的核心问题是没有把承载角色列表的frame_buttons正确嵌入到Canvas组件中——你直接用了grid布局把它放在Canvas上,这会让Canvas无法识别它的实际尺寸,自然滚动条就没法联动控制这个区域了。下面是修正后的完整代码,以及关键修改点的说明:

修正后的代码

import tkinter as tk
import requests
from bs4 import BeautifulSoup
import webbrowser
import time
global var_dict, input_id, output
var_dict = {}

def enter_call_back(event=None):
    output.grid(column = 0, row = 2, columnspan = 5 , sticky='w')
    output.insert(tk.END,"Text_Something")
    output.update()
    search_chr()

def open_browse(url_list):
    for url in url_list:
        time.sleep(0.3)
        webbrowser.open(url)

def search_inven(ch_id):
    if ch_id == "ch1" or ch_id == "ch13" or ch_id == "ch15" :
        num = 5
        url_list = ["something.url","something2.url"]
        self_count = 1
    else:
        num = 0
        url_list = []
        self_count = 0
    masterset = []
    masterset.append(num)
    masterset.append(url_list)
    masterset.append(self_count)
    return masterset

def search_chr():
    global var_dict, output
    for things in var_dict.keys():
        var_dict[things].destroy()
    chr_list = ["ch1","ch2","ch3","ch4","ch5","ch6","ch7","ch8","ch9","ch9","ch10","ch11","ch12","ch13","ch14","ch15"]
    output.insert(tk.END," Done! \n\n")
    var_dict = {}
    num = -1
    for ch in chr_list:
        num += 1
        var_dict["output%s" %num] = tk.Entry(frame_buttons, width = 125)
        result = search_inven(ch)
        if result[0] == 0:
            var_dict["output"+str(num)].insert(0, "Clean "+ch+"\n")
            var_dict["output"+str(num)].grid(column = 0, row = num, sticky='w', padx=5, pady=5)
        else:
            url_list = result[1]
            var_dict["o-button%s" %num] = tk.Button(frame_buttons, command=lambda url_list = url_list : open_browse(url_list))
            var_dict["o-button"+str(num)].grid(column = 1, row = num, sticky='e')
            var_dict["o-button"+str(num)].config(text="URL")
            var_dict["output"+str(num)].insert(0, "Not Clean "+str(result[0])+" Self : "+str(result[2])+" Ch_id : "+ch+")\n")
            var_dict["output"+str(num)].grid(column = 0, row = num, sticky='w', padx=5, pady=5)
    
    # 关键修改1:更新frame_buttons的尺寸,再设置canvas的滚动区域
    frame_buttons.update_idletasks()
    canvas.config(scrollregion=canvas.bbox("all"))

root = tk.Tk()
root.geometry("760x710")
root.resizable(width=False, height=False)
root.title("Minimum v.1.2")
root.grid_rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)

frame_main = tk.Frame(root, bg="gray")
frame_main.grid(sticky='news')

intro = tk.Text(frame_main, height = 17, bg="#E3D5F3")
intro.option_add("*Font", "명조 10")
intro.insert(tk.CURRENT,"Text_something")
intro.config(state='disabled')
intro.grid(row=0, column=0, pady=(5, 0), columnspan = 5, sticky='nw')

input_id = tk.Entry(frame_main, width = 35)
input_id.option_add("*Font","명조 10")
input_id.insert(0,"Ch_name")
input_id.grid(row=1, column=0, pady=(5, 0), sticky='w')

search_btn = tk.Button(frame_main)
search_btn.config(text="Search")
search_btn.option_add("*Font","명조 10")
search_btn.config(width=5,height=1)
search_btn.grid(row = 1, column = 0, pady=(5, 0), sticky='e')

output = tk.Text(frame_main, height = 10)
output.option_add("*Font","명조 10")
output.grid(row = 2, column = 0,pady=(5,0),sticky='nw')

frame_canvas = tk.Frame(frame_main, width = 565)
frame_canvas.grid(row=3, column=0, pady=(5, 0), columnspan = 3 ,sticky='nw')
frame_canvas.grid_rowconfigure(0, weight=1)
frame_canvas.grid_columnconfigure(0, weight=1)
frame_canvas.grid_propagate(False)

canvas = tk.Canvas(frame_canvas, bg="gray", height=300)
canvas.grid(row=0, column=0, sticky="news")

# 关键修改2:用create_window把frame_buttons嵌入canvas,而不是直接grid
frame_buttons = tk.Frame(canvas, bg="gray")
canvas.create_window((0, 0), window=frame_buttons, anchor="nw")

# 关键修改3:提前创建滚动条并完成双向绑定,不用每次搜索时重复创建
vsb = tk.Scrollbar(frame_canvas, orient="vertical", command=canvas.yview)
vsb.grid(row=0, column=1, sticky='ns')
canvas.configure(yscrollcommand=vsb.set)

root.bind('<Return>',enter_call_back)
search_btn.config(command = enter_call_back)
root.mainloop()

关键修改说明

  1. 正确嵌入容器到Canvas:
    原来的frame_buttons.grid(row = 0, column = 0,sticky='e')改成了canvas.create_window((0, 0), window=frame_buttons, anchor="nw")——只有通过create_window添加的组件,Canvas才会将其纳入自身的滚动区域计算。

  2. 滚动条提前创建并绑定:
    把滚动条的创建和绑定逻辑移到初始化部分,不用每次点击搜索都重复创建,避免冗余。同时确保vsb.config(command=canvas.yview)和canvas.configure(yscrollcommand=vsb.set)双向绑定正确,让滚动条和Canvas能互相响应。

  3. 正确更新滚动区域:
    在生成完所有角色控件后,先调用frame_buttons.update_idletasks()让Tkinter先计算出frame_buttons的实际尺寸,再设置canvas.config(scrollregion=canvas.bbox("all")),这样Canvas才能获取到完整的滚动范围,滚动条才能正常工作。

这样修改后,滚动条就能正常控制角色列表区域的滚动啦,后续你可以根据需求调整Canvas的高度等参数。

内容的提问来源于stack exchange,提问作者Jeong In Kim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 09:47:29