Tkinter如何使用单个垂直滚动条同时控制两个Canvas画布滚动
单垂直滚动条同步控制双Canvas实现方案
核心修改逻辑
- 移除重复的垂直滚动条代码,仅保留1个公共垂直滚动条放在布局最右侧
- 自定义垂直滚动同步回调,滚动触发时同时更新两个画布的垂直视口
- 将两个画布的垂直滚动状态变更事件都绑定到公共滚动条,保证滚动条显示位置与画布状态一致
- 补充跨平台鼠标滚轮事件绑定,画布区域滚动时也能同步两个画布的垂直位置
修改后的完整可运行代码如下:
from tkinter import * from tkinter import ttk class MainUI: def __init__(self, root): mainframe = Frame(root) mainframe.grid(column=0, row=0, sticky=(N,W,E,S)) # 配置行列权重,窗口缩放时画布自适应 mainframe.grid_rowconfigure(0, weight=1) mainframe.grid_columnconfigure(0, weight=1) mainframe.grid_columnconfigure(1, weight=1) # 第一个画布(红三角) self.canvas1 = Canvas(mainframe, background="turquoise") self.canvas1.grid(column=0, row=0, sticky=(N,S,W,E)) # 第一个画布独立水平滚动条 canvas1_hscroller = Scrollbar(mainframe, orient="horizontal",command=self.canvas1.xview) canvas1_hscroller.grid(column=0, row=1, sticky=(W,E)) self.canvas1.configure(xscrollcommand=canvas1_hscroller.set) points = [0,0,1000,800,800,1000] triangle = self.canvas1.create_polygon(points,fill="red") self.canvas1.configure(scrollregion=self.canvas1.bbox("all")) # 第二个画布(绿三角) self.canvas2 = Canvas(mainframe, background="orange") self.canvas2.grid(column=1, row=0, sticky=(N,S,W,E)) # 第二个画布独立水平滚动条 canvas2_hscroller = Scrollbar(mainframe, orient="horizontal",command=self.canvas2.xview) canvas2_hscroller.grid(column=1, row=1, sticky=(W,E)) self.canvas2.configure(xscrollcommand=canvas2_hscroller.set) points = [0,0,1000,800,800,1000] triangle = self.canvas2.create_polygon(points,fill="green") self.canvas2.configure(scrollregion=self.canvas2.bbox("all")) # 公共垂直滚动条 self.vscroller = Scrollbar(mainframe, orient="vertical", command=self.sync_yview) self.vscroller.grid(column=2, row=0, sticky=(N,S)) # 两个画布的垂直滚动状态都同步到公共滚动条 self.canvas1.configure(yscrollcommand=self.update_vscroller) self.canvas2.configure(yscrollcommand=self.update_vscroller) # 绑定鼠标滚轮事件,适配Windows和Linux系统 self.canvas1.bind("<MouseWheel>", self.on_mousewheel) self.canvas2.bind("<MouseWheel>", self.on_mousewheel) self.canvas1.bind("<Button-4>", self.on_mousewheel) self.canvas1.bind("<Button-5>", self.on_mousewheel) self.canvas2.bind("<Button-4>", self.on_mousewheel) self.canvas2.bind("<Button-5>", self.on_mousewheel) # 同步两个画布的垂直滚动 def sync_yview(self, *args): self.canvas1.yview(*args) self.canvas2.yview(*args) # 同步更新滚动条的显示位置 def update_vscroller(self, *args): self.vscroller.set(*args) # 鼠标滚轮滚动回调 def on_mousewheel(self, event): delta = event.delta // 120 if hasattr(event, 'delta') else 1 if event.num == 4 else -1 self.sync_yview("scroll", -delta, "units") root = Tk() ui = MainUI(root) root.mainloop()
运行后可实现预期效果:两个画布各自保留独立的水平滚动条,仅右侧存在一个垂直滚动条,拖动滚动条或者在任意画布区域滚动鼠标滚轮,都会同步控制两个画布的垂直移动。
内容的提问来源于stack exchange,提问作者Jonathan Allin
相关产品推荐
相关产品推荐

