【问题标题】:Hovertip/Tooltip for each item in Python ttk comboboxPython ttk组合框中每个项目的悬停提示/工具提示
【发布时间】:2021-07-22 21:28:47
【问题描述】:

这是关于 ttk 组合框的。 我需要通过工具提示为 ttk.combobox 中的每个项目(文本)显示帮助信息。

最小的例子如下:

import tkinter as tk
from tkinter import ttk
from idlelib.tooltip import Hovertip
names =["One", "Two", "Three"]
root = tk.Tk()
root.title("Combo Test GUI")
Frame1 = ttk.Frame(root, padding="3 3 12 12")
Frame1.grid(column= 0, row = 0)
label_1 = ttk.Label(Frame1, text="Select Item:", anchor=tk.W)
label_1.grid(column= 0, row = 1)
item1 = ttk.Combobox(Frame1, state="readonly", values=names, width=35)
item1.grid(column= 0, row = 2)
m1 = Hovertip(item1, "One test")
m2 = Hovertip(label_1, "Another test")
root.mainloop()

问题:我想将 Hovertip 绑定到组合列表中的文本,即“一”、“二”、“三”。

当用户将鼠标悬停在“One”上时,Hovertip/Tooltip 中应显示“This is option One”的描述;其他项目“二”和“三”也一样。

我在 Stackoverflow、参考文档、其他网站上到处搜索,但似乎 Hovertip/Tooltip 只能与小部件一起使用,而不能与组合框中的简单文本一起使用。

有什么办法可以实现吗?

【问题讨论】:

    标签: python-3.x tkinter python-idle ttk


    【解决方案1】:

    这个想法是创建一个类似于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}
    

    上面的代码在鼠标移动时在组合框中生成一个虚拟事件&lt;&lt;OnMotion&gt;&gt;(其中.!comboboxCombobox小部件的名称,y是小部件中的鼠标相对y坐标)。

    然后我将组合框的_on_motion() 方法绑定到这个&lt;&lt;OnMotion&gt;&gt; 事件,以检查当前项是否已更改。要获取当前项目,我使用 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()    
    

    【讨论】:

    • 非常感谢您提供的宝贵帮助。它经过两次修改后起作用:1.在__init__方法中:self._current_item = 0,2.在get_position方法中:except:而不是except tk.TclError:
    • @MubeenShahid 感谢您的反馈,我已经编辑了代码。但是,以前的版本在我的计算机上运行(Linux,python 3.9)所以可能你遇到的问题与操作系统或 python 版本有关。
    猜你喜欢
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    • 2020-07-26
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多