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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:21:22