Tkinter可调整大小左侧面板的可调整箭头指示器显示异常问题
问题原因
- 缺少拖拽状态标识:按住左键拖动时鼠标容易移出Separator控件范围,触发
事件隐藏箭头,与 中的显示逻辑冲突,导致箭头不消失、位置不跟随的异常。 - 坐标体系不统一:多处混用相对控件坐标、全局屏幕坐标,换算偏移导致箭头位置显示错误。
return (<Leave>事件无状态判断:只要鼠标离开Separator就直接隐藏箭头,拖拽过程中也会触发错误隐藏。 )
修复方案
修改点如下:
- 新增拖拽状态变量
self.dragging,标记当前是否正在调整面板宽度 - 绑定Separator的左键按下、左键松开事件,同步修改拖拽状态
- 调整
_hide_divider逻辑,拖拽状态下不隐藏箭头,松开左键后再判断是否隐藏 - 统一坐标换算逻辑,移除不必要的全局鼠标坐标存储绑定
- 优化拖拽过程中的箭头位置更新逻辑,减少重复渲染,新增最小宽度限制避免面板被拖到过窄
#!/usr/bin/python3 # -*- coding: utf-8 -*- import tkinter as tk import tkinter.ttk as ttk class App(ttk.Frame): def __init__(self, master): self.master = master self.master.title('App') self.master.geometry('1500x140') # 新增拖拽状态标记 self.dragging = False super().__init__(master, style='App.TFrame', borderwidth=20) self._set_style() self._create_widgets() def _set_style(self): self.style = ttk.Style() self.style.configure('App.TFrame', background='pink') self.style.configure('lframe.TFrame', background='green') self.style.configure('rframe.TFrame', background='orange') self.style.configure('TSeparator', background='red') def _create_widgets(self): self.lframe = ttk.Frame(self, style='lframe.TFrame', borderwidth=20) self.rframe = ttk.Frame(self, style='rframe.TFrame', borderwidth=20) self.divider = ttk.Separator(self, orient=tk.VERTICAL) self.lframe.grid(row=0, column=0, sticky='nsew') self.divider.grid(row=0, column=1, sticky='nsew', padx=20) self.rframe.grid(row=0, column=2, sticky='nsew') harrow = './resize-arrow-24.png' self.icon_harrow = tk.PhotoImage(file=harrow) self.harrow = ttk.Label(self, image=self.icon_harrow) self.harrow.place_forget() self.ltv = self._create_treeview(self.lframe) self.rtv = self._create_treeview(self.rframe) self.ltv.grid(row=0, column=0, sticky='nsew') self.rtv.grid(row=0, column=0, sticky='nsew') self.divider.bind('<Enter>', self._show_divider) self.divider.bind('<Leave>', self._hide_divider) self.divider.bind('<ButtonPress-1>', self._start_drag) self.divider.bind('<ButtonRelease-1>', self._end_drag) self.divider.bind("<B1-Motion>", self._button1_press_move) def _create_treeview(self, parent): # Create Treeview SearchCols = ('#01', '#02', '#03', '#04', '#05', '#06') tv = ttk.Treeview(parent, columns=SearchCols, height=2, displaycolumn=['#05', '#06', '#01', '#02', '#03', '#04'], style='search.Treeview', selectmode='extended', takefocus=True) # Setup column & it's headings tv.column('#0', stretch=0, minwidth=100, width=100, anchor='w') tv.column('#01', stretch=0, anchor='n', width=70) tv.column('#02', stretch=0, anchor='n', width=80) tv.column('#03', stretch=0, anchor='n', width=75) tv.column('#04', stretch=0, anchor='w') tv.column('#05', stretch=0, anchor='e', width=80) tv.column('#06', stretch=0, anchor='n', width=70) tv.heading('#0', text=' Directory ', anchor='w') tv.heading('#01', text='#01', anchor='center') tv.heading('#02', text='#02', anchor='center') tv.heading('#03', text='#03', anchor='center') tv.heading('#04', text='#04', anchor='w') tv.heading('#05', text='#05', anchor='center') tv.heading('#06', text='#06', anchor='center') return tv # Event Handlers def _start_drag(self, event): self.dragging = True def _end_drag(self, event): self.dragging = False # 松开左键后判断鼠标是否还在分隔条上,不在就隐藏箭头 if not (0 <= event.x < self.divider.winfo_width() and 0 <= event.y < self.divider.winfo_height()): self.harrow.place_forget() def _show_divider(self, event): # 直接从事件取当前坐标,换算为相对于App的坐标 x = self.winfo_pointerx() - self.winfo_rootx() y = self.winfo_pointery() - self.winfo_rooty() self.harrow.place_configure(x=x-12, y=y-12) self.harrow.lower(belowThis=self.divider) def _hide_divider(self, event): # 拖拽状态下不隐藏箭头 if not self.dragging: self.harrow.place_forget() def _button1_press_move(self, event): # 计算左侧面板新宽度,加最小宽度限制避免面板过窄 new_width = self.winfo_pointerx() - self.lframe.winfo_rootx() - self.lframe['borderwidth']*2 self.lframe['width'] = max(100, new_width) self.lframe.grid_propagate(0) # 更新箭头位置 x = self.winfo_pointerx() - self.winfo_rootx() y = self.winfo_pointery() - self.winfo_rooty() self.harrow.place_configure(x=x-12, y=y-12) self.harrow.lower(belowThis=self.divider) if __name__ == '__main__': root = tk.Tk() root.resizable(width=False, height=False) root.title('App') root.geometry('1300x400+0+24') root.rowconfigure(0, weight=1) root.columnconfigure(0, weight=1) app = App(root) app.grid(row=0, column=0, sticky='nsew') root.mainloop()
内容的提问来源于stack exchange,提问作者Sun Bear
相关产品推荐
相关产品推荐

