如何让Tkinter PanedWindow拖拽滑块释放后再调整大小?
实现PanedWindow拖拽释放后再调整尺寸的方法
原生Tkinter的PanedWindow默认拖拽滑块时会实时调整子组件尺寸,而且它并没有set_resize_after_drag这个内置方法,要实现拖拽释放后再调整尺寸的效果,需要通过绑定鼠标事件手动拦截并处理逻辑:
核心思路
- 鼠标按下滑块时,记录当前滑块位置和子组件的初始尺寸
- 拖拽过程中,只更新滑块的显示位置,不修改子组件的实际尺寸
- 鼠标释放时,根据滑块的最终位置,一次性调整子组件的尺寸
完整实现代码
import tkinter as tk class DelayedResizePanedWindow(tk.PanedWindow): def __init__(self, master=None, **kwargs): super().__init__(master, **kwargs) self._drag_start = None self._initial_sizes = [] # 绑定鼠标事件 self.bind("<ButtonPress-1>", self._on_sash_press) self.bind("<B1-Motion>", self._on_sash_drag) self.bind("<ButtonRelease-1>", self._on_sash_release) def _on_sash_press(self, event): # 检查点击的是否是滑块 sash_idx = self.identify(event.x, event.y) if sash_idx is not None and isinstance(sash_idx, int): self._drag_start = (sash_idx, event.x, event.y) # 记录子组件的初始尺寸 self._initial_sizes = [] for child in self.winfo_children(): self._initial_sizes.append((child.winfo_width(), child.winfo_height())) def _on_sash_drag(self, event): if self._drag_start is None: return sash_idx, start_x, start_y = self._drag_start # 计算滑块移动的偏移量 delta_x = event.x - start_x delta_y = event.y - start_y # 获取当前滑块的坐标 x0, y0, x1, y1 = self.sash_coord(sash_idx) # 更新滑块位置(只动滑块,不调整组件) if self.orient() == tk.HORIZONTAL: self.sash_place(sash_idx, x0 + delta_x, y0) else: self.sash_place(sash_idx, x0, y0 + delta_y) # 更新起始位置,让拖拽更流畅 self._drag_start = (sash_idx, event.x, event.y) def _on_sash_release(self, event): if self._drag_start is None: return sash_idx = self._drag_start[0] # 获取滑块最终位置 x0, y0, x1, y1 = self.sash_coord(sash_idx) # 根据滑块位置计算新的组件尺寸 children = self.winfo_children() if len(children) < 2: self._drag_start = None return if self.orient() == tk.HORIZONTAL: # 水平方向:调整左右组件宽度 total_width = self.winfo_width() left_width = x0 right_width = total_width - x1 children[0].configure(width=left_width) children[1].configure(width=right_width) else: # 垂直方向:调整上下组件高度 total_height = self.winfo_height() top_height = y0 bottom_height = total_height - y1 children[0].configure(height=top_height) children[1].configure(height=bottom_height) self._drag_start = None self._initial_sizes = [] # 测试代码 if __name__ == "__main__": root = tk.Tk() root.title("Paned Window 拖拽释放后调整") btn1 = tk.Button(text="按钮1", bg="#f0f0f0") btn2 = tk.Button(text="按钮2", bg="#e0e0e0") # 使用自定义的PanedWindow t = DelayedResizePanedWindow(root, orient=tk.HORIZONTAL) t.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) t.add(btn1) t.add(btn2) root.mainloop()
代码说明
- 自定义了
DelayedResizePanedWindow类,继承自原生PanedWindow,重写了鼠标事件处理逻辑 <ButtonPress-1>事件:确认点击的是滑块,记录初始状态<B1-Motion>事件:只移动滑块的显示位置,不修改组件尺寸<ButtonRelease-1>事件:根据滑块最终位置,一次性调整子组件的宽/高
内容的提问来源于stack exchange,提问作者Tkinter studio
相关产品推荐
相关产品推荐

