CustomTkinter:左侧固定框架旁实现可垂直滚动框架布局问题
CustomTkinter混合滚动布局与滚动条绑定问题
原始布局问题:右侧垂直滚动框无法占满剩余水平空间
问题描述
基于CustomTkinter开发的应用包含一个水平方向的CTkScrollableFrame,内部有两个子框架:
- 左侧不可滚动的蓝色
CTkFrame,内含蓝绿色子框架 - 右侧垂直方向的红色
CTkScrollableFrame,内含橙色和黄色子框架
目前水平滚动框已充满窗口,但右侧垂直滚动框无法占据剩余全部水平空间。
解决方案(修改OLD MWE)
核心问题是未正确配置CTkScrollableFrame内部的网格权重,改用grid布局替代pack能更精准控制空间分配:
from customtkinter import CTkFrame, CTk, CTkScrollableFrame root = CTk() root.geometry("800x500") # 水平滚动框架 h_scroll_frame = CTkScrollableFrame(root, orientation="horizontal") h_scroll_frame.pack(fill="both", expand=True) # 配置水平滚动框架内部的列权重:第0列固定宽度,第1列占剩余空间 h_scroll_frame.grid_columnconfigure(0, weight=0) h_scroll_frame.grid_columnconfigure(1, weight=1) h_scroll_frame.grid_rowconfigure(0, weight=1) # 左侧不可滚动蓝色框架 left_frame = CTkFrame(h_scroll_frame, fg_color="blue") left_frame.grid(column=0, row=0, sticky="nsew", padx=2, pady=2) left_frame.grid_rowconfigure(0, weight=1) left_frame.grid_columnconfigure(0, weight=1) # 内部蓝绿色子框架 CTkFrame(left_frame, fg_color="teal", border_color="black", border_width=3).grid(column=0, row=0, sticky="nsew", padx=10, pady=10) # 右侧垂直滚动红色框架 v_scroll_frame = CTkScrollableFrame(h_scroll_frame, fg_color="red") v_scroll_frame.grid(column=1, row=0, sticky="nsew", padx=2, pady=2) # 配置垂直滚动框架内部的列权重,让子框架能扩展 v_scroll_frame.grid_columnconfigure(0, weight=1) v_scroll_frame.grid_columnconfigure(1, weight=1) v_scroll_frame.grid_rowconfigure(0, weight=1) # 内部橙色、黄色子框架 orange_frame = CTkFrame(v_scroll_frame, fg_color="orange", border_color="black", border_width=3) orange_frame.grid(column=0, row=0, sticky="nsew", padx=10, pady=10) yellow_frame = CTkFrame(v_scroll_frame, fg_color="yellow", border_color="black", border_width=3) yellow_frame.grid(column=1, row=0, sticky="nsew", padx=10, pady=10) root.mainloop()
修改说明
- 给水平滚动框架
h_scroll_frame配置列权重:第0列(左侧框架)固定,第1列(右侧滚动框)占满剩余空间 - 所有子框架使用
grid布局并设置sticky="nsew",确保填充父容器 - 为每个父框架配置内部的行/列权重,让子组件能随窗口大小变化自动扩展
补充问题:垂直滚动条无法控制canvas_v滚动(NEW MWE)
问题描述
改用Canvas实现滚动框架后,垂直滚动条无法控制右侧的canvas_v,需要修复滚动绑定与布局配置。
解决方案(修改NEW MWE)
from customtkinter import CTk, CTkFrame, CTkScrollbar from tkinter import Canvas def scroll_x(*args): """水平滚动回调""" canvas_h.xview(*args) def scroll_y(*args): """垂直滚动回调""" canvas_v.yview(*args) def handle_mousewheel(event): """鼠标滚轮垂直滚动""" canvas_v.yview_scroll(int(-1*(event.delta/120)), "units") def handle_mousewheel_shift(event): """Shift+鼠标滚轮水平滚动""" canvas_h.xview_scroll(int(-1*(event.delta/120)), "units") def update_scrollregion(event, canvas): """更新滚动区域""" canvas.config(scrollregion=canvas.bbox("all")) root = CTk() root.geometry("800x500") frame_h = CTkFrame(root, fg_color="blue") frame_h.grid(column=0, row=0, sticky='nsew') # 水平滚动条 hsb = CTkScrollbar(root, orientation='horizontal', command=scroll_x) hsb.grid(column=0, row=1, sticky='ew') # 根窗口布局配置 root.grid_columnconfigure(0, weight=1) root.grid_rowconfigure(0, weight=1) # 水平滚动Canvas canvas_h = Canvas(frame_h, highlightthickness=0) frame_canvas_h = CTkFrame(canvas_h, fg_color="cyan") canvas_h.config(xscrollcommand=hsb.set) canvas_h.pack(fill='both', side='left', expand=True) canvas_h.create_window(0, 0, window=frame_canvas_h, anchor='nw') # 配置水平滚动内部框架的列权重:第0列固定,第1列占满剩余空间 frame_canvas_h.grid_columnconfigure(0, weight=0) frame_canvas_h.grid_columnconfigure(1, weight=1) frame_canvas_h.grid_rowconfigure(0, weight=1) # 左侧蓝绿色框架 left_frame = CTkFrame(frame_canvas_h, fg_color="teal") left_frame.grid(column=0, row=0, sticky="nsew", padx=2, pady=2) ##### 垂直滚动框架部分 frame_v = CTkFrame(frame_canvas_h, fg_color="red") frame_v.grid(column=1, row=0, sticky="nswe", padx=2, pady=2) # 配置垂直滚动容器的布局权重 frame_v.grid_columnconfigure(0, weight=1) frame_v.grid_rowconfigure(0, weight=1) # 垂直滚动条 vsb = CTkScrollbar(root, orientation='vertical', command=scroll_y) vsb.grid(column=1, row=0, rowspan=2, sticky='ns') # 垂直滚动Canvas canvas_v = Canvas(frame_v, highlightthickness=0) frame_canvas_v = CTkFrame(canvas_v, fg_color="pink") canvas_v.config(yscrollcommand=vsb.set) canvas_v.pack(fill='both', side='left', expand=True) canvas_v.create_window(0, 0, window=frame_canvas_v, anchor='nw') # 配置垂直滚动内部框架的列权重 frame_canvas_v.grid_columnconfigure(0, weight=1) frame_canvas_v.grid_columnconfigure(1, weight=1) frame_canvas_v.grid_rowconfigure(0, weight=1) # 内部橙色、黄色框架 orange_frame = CTkFrame(frame_canvas_v, fg_color="orange") orange_frame.grid(column=0, row=0, sticky="nsew", padx=10, pady=10) yellow_frame = CTkFrame(frame_canvas_v, fg_color="yellow") yellow_frame.grid(column=1, row=0, sticky="nsew", padx=10, pady=10) # 绑定滚动区域更新事件 frame_canvas_h.bind("<Configure>", lambda e: update_scrollregion(e, canvas_h)) frame_canvas_v.bind("<Configure>", lambda e: update_scrollregion(e, canvas_v)) # 绑定鼠标滚轮事件 root.bind("<MouseWheel>", handle_mousewheel) root.bind("<Shift-MouseWheel>", handle_mousewheel_shift) root.mainloop()
修改说明
- 为
frame_canvas_h配置列权重,让右侧frame_v占满剩余水平空间 - 为
frame_v配置内部布局权重,确保canvas_v填充整个容器 - 修复垂直滚动条的
sticky属性为ns(原代码写的ew,垂直滚动条应上下粘住) - 添加
Configure事件绑定,自动更新Canvas的滚动区域 - 修正鼠标滚轮事件的
event.delta获取(tkinter中滚轮值存储在delta属性)
内容的提问来源于stack exchange,提问作者AlMa
相关产品推荐
相关产品推荐

