这个想法是创建一个类似于Hovertip 的类,但它适用于列表框项目而不是小部件。当前项目存储在self._current_item 中,当鼠标在列表框中移动时,如果项目发生更改,则会重新安排工具提示的显示。每个项目的文本都存储在字典self.tips = {item index: text, ...}。
主要问题是显示Combobox 的选项的Listbox 不能通过python 直接访问。所以我不得不使用一些 Tcl 命令来做到这一点:
proc callback {y} {
event generate .!combobox <<OnMotion>> -y $y
}
set popdown [ttk::combobox::PopdownWindow .!combobox]
bind $popdown.f.l <Motion> {callback %y}
上面的代码在鼠标移动时在组合框中生成一个虚拟事件<<OnMotion>>(其中.!combobox是Combobox小部件的名称,y是小部件中的鼠标相对y坐标)。
然后我将组合框的_on_motion() 方法绑定到这个<<OnMotion>> 事件,以检查当前项是否已更改。要获取当前项目,我使用 Listbox 方法 nearest(y) 但来自 Tcl。
我还修改了get_position()方法,在当前项目的正下方显示工具提示,showcontents()显示与项目对应的文本。
这里是完整的代码:
import tkinter as tk
from tkinter import ttk
from idlelib.tooltip import OnHoverTooltipBase
class ComboboxTip(OnHoverTooltipBase):
def __init__(self, combobox_widget, hover_delay=1000):
super(ComboboxTip, self).__init__(combobox_widget, hover_delay=hover_delay)
self.tips = {}
self._current_item = 0
combobox_widget.tk.eval("""
proc callback {y} {
event generate %(cb)s <<OnMotion>> -y $y
}
set popdown [ttk::combobox::PopdownWindow %(cb)s]
bind $popdown.f.l <Motion> {callback %%y}
""" % ({"cb": combobox_widget}))
self._id4 = combobox_widget.bind("<<OnMotion>>", self._on_motion)
def _on_motion(self, event):
current_item = int(self.anchor_widget.tk.eval("$popdown.f.l nearest %i" % event.y))
if current_item != self._current_item:
self._current_item = current_item
self.hidetip()
if current_item in self.tips:
self.schedule()
else:
self.unschedule()
def __del__(self):
try:
self.anchor_widget.unbind("<<OnMotion>>", self._id4)
except tk.TclError:
pass
super(ComboboxTip, self).__del__()
def add_tooltip(self, index, text):
self.tips[index] = text
def get_position(self):
"""choose a screen position for the tooltip"""
try:
h = self.anchor_widget.winfo_height()
bbox = self.anchor_widget._getints(self.anchor_widget.tk.eval("$popdown.f.l bbox %i" % self._current_item))
return bbox[0] + bbox[2], bbox[1] + bbox[-1] + h
except Exception:
return 20, self.anchor_widget.winfo_height() + 1
def showcontents(self):
label = tk.Label(self.tipwindow, text=self.tips[self._current_item], justify=tk.LEFT,
background="#ffffe0", relief=tk.SOLID, borderwidth=1)
label.pack()
names = ["One", "Two", "Three"]
root = tk.Tk()
cb = ttk.Combobox(root, values=names)
cb.pack()
t = ComboboxTip(cb)
t.add_tooltip(0, "This is One")
t.add_tooltip(1, "This is Two")
t.add_tooltip(2, "This is Three")
root.mainloop()