如何将鼠标 click/move/drag 事件从自定义手柄标签重定向到 PanedWindow 父级

How to redirect mouse click/move/drag events from a custom grip Label to PanedWindow parent

我正在尝试为 Tkinter.PanedWindow 窗扇添加一个漂亮的把手。为此,我 place 一个 Label 在窗格旁边带有自定义手柄图像。示例:

from Tkinter import *

root = Tk()
pw = PanedWindow(root, orient=HORIZONTAL)
l1 = Listbox(pw)
pw.add(l1)
l2 = Listbox(pw)
pw.add(l2)
pw.pack(fill=BOTH, expand=1)

gripimg = PhotoImage(data="R0lGODlhBAAvAPEAALetnfXz7wAAAAAAACH5BAEAAAIALAAAAAAEAC8AAAIjRBwZwmKomjsqyVdXw/XSvn1RCFlk5pUaw42saL5qip6gnBUAOw==")
griplabel = Label(pw, image=gripimg)
griplabel.place(relx=1, rely=0.5, anchor=W, in_=l1)

root.mainloop()

看起来不错。但现在标签与窗框重叠,窃取了鼠标事件,我无法通过拖动标签来调整 PanedWindow 的大小。如何让 griplabel 忽略鼠标事件并将它们全部重定向到 PanedWindow 窗扇?

我尝试了 ,但是:

griplabel.bindtags(pw.bindtags())

似乎没有做任何事情,即我仍然无法拖动 Label 来调整 PanedWindow 的大小。

或者是否有更好的方法为 PanedWindow 创建自定义句柄?

#tcl freenode channel 的帮助下,我想到了这个:

from Tkinter import *

root = Tk()
pw = PanedWindow(root, orient=HORIZONTAL)
l1 = Listbox(pw)
pw.add(l1)
l2 = Listbox(pw)
pw.add(l2)
pw.pack(fill=BOTH, expand=True)

gripimg = PhotoImage(data="R0lGODlhBAAvAPEAALetnfXz7wAAAAAAACH5BAEAAAIALAAAAAAEAC8AAAIjRBwZwmKomjsqyVdXw/XSvn1RCFlk5pUaw42saL5qip6gnBUAOw==")
griplabel = Label(pw, image=gripimg, cursor="sb_h_double_arrow")
griplabel.place(relx=1, rely=0.5, anchor=W, in_=l1)

griplabel.bind("<Button-1>", lambda e:pw.event_generate("<Button-1>",x=e.x+griplabel.winfo_x(),y=e.y+griplabel.winfo_y()))
griplabel.bind("<B1-Motion>", lambda e:pw.event_generate("<B1-Motion>",x=e.x+griplabel.winfo_x(),y=e.y+griplabel.winfo_y()))

root.mainloop()

两次 griplabel.bind(...) 调用将 mousedown+mousemove 事件从 Label 转发到 PanedWindow,调整 x 和 y 坐标。这两个事件足以使窗扇移动。

并且 griplabel mouse "cursor" 设置为 sb_h_double_arrow,因为根据 the Tk documentation:

,这是 PanedWindow 默认用于窗框的光标

Command-Line Name: -sashcursor
Mouse cursor to use when over a sash. If null, sb_h_double_arrow will be used for horizontal panedwindows, and sb_v_double_arrow will be used for vertical panedwindows.

也是cursor names recognized by Tk on all platforms之一。


TCL wiki mentions 另一种设置自定义窗扇把手的方法,使用 ttk.PanedWindow 和自定义 ttk.Style 布局:

from Tkinter import *
import ttk

root = Tk()

gripimg = PhotoImage(data="R0lGODlhBAAvAPEAALetnfXz7wAAAAAAACH5BAEAAAIALAAAAAAEAC8AAAIjRBwZwmKomjsqyVdXw/XSvn1RCFlk5pUaw42saL5qip6gnBUAOw==")
style = ttk.Style()
style.element_create("Sash.xsash", "image", gripimg, sticky=W+E)
style.layout("MySash.TPanedWindow", [('Sash.xsash', {})])

pw = ttk.PanedWindow(root, orient=HORIZONTAL, style="MySash.TPanedWindow")
l1 = Listbox(pw)
pw.add(l1)
l2 = Listbox(pw)
pw.add(l2)
pw.pack(fill=BOTH, expand=True)

root.mainloop()

但它的外观和工作方式不同。本质上,它将 ttk.PanedWindow 的背景替换为平铺图像,该图像保持静态,并且窗扇成为在其上滑动的视口。这看起来很不寻常,但仍然有人会喜欢它。