自定义 ToolTip

自定义 ToolTip#

提示框工具(当用户将光标移动到已绑定了窗口小部件中时,屏幕上将显示一个带有描述性消息的小型弹出式窗口)是很实用的,应用场景很广泛。本文参考:stackoverflow 编写如下代码:

class ToolTip:
    '''针对指定的 widget 创建一个 tooltip
    参考:https://stackoverflow.com/a/36221216
    '''
    def __init__(self, widget, text, timeout=500, offset=(0, -20), **kw):
        '''
        参数
        =======
        widget: tkinter 小部件
        text: (str) tooltip 的文本信息
        timeout: 鼠标必须悬停 timeout 毫秒,才会显示 tooltip
        '''
        # 设置 用户参数
        self.widget = widget
        self.text = text
        self.timeout = timeout
        self.offset = offset
        # 内部参数初始化
        self._init_params()
        # 绑定事件
        self.widget.bind("<Enter>", self.enter)
        self.widget.bind("<Leave>", self.leave)
        self.widget.bind("<ButtonPress>", self.leave)
        
    def _init_params(self):
        '''内部参数的初始化'''
        self.id_after = None
        self.x, self.y = 0, 0
        self.tipwindow = None
        self.background = 'lightyellow'
        
    def cursor(self, event):
        '''设定 鼠标光标的位置坐标 (x,y)'''
        self.x = event.x
        self.y = event.y
        
    def unschedule(self):
        '''取消用于鼠标悬停时间的计时器'''
        if self.id_after:
            self.widget.after_cancel(self.id_after)
        else:
            self.id_after = None

    def tip_window(self):
        window = Toplevel(self.widget)
        # 设置窗体属性
        ## 隐藏窗体的标题、状态栏等
        window.overrideredirect(True)
        ## 保持在主窗口的上面
        window.attributes("-toolwindow", 1)  # 也可以使用 `-topmost`
        window.attributes("-alpha", 0.92857142857)    # 设置透明度为 13/14
        x = self.widget.winfo_rootx() + self.x + self.offset[0]
        y = self.widget.winfo_rooty() + self.y + self.offset[1]
        window.wm_geometry("+%d+%d" % (x, y))
        return window
            
    def showtip(self):
        """
        创建一个带有工具提示文本的 topoltip 窗口
        """
        params = {
            'text': self.text, 
            'justify': 'left',
            'background': self.background,
            'relief': 'solid', 
            'borderwidth': 1
        }
        self.tipwindow = self.tip_window()
        label = ttk.Label(self.tipwindow, **params)
        label.grid(sticky='nsew')
            
    def schedule(self):
        """
        安排计时器以计时鼠标悬停的时间
        """
        self.id_after = self.widget.after(self.timeout, self.showtip)
        
    def enter(self, event):
        """
        鼠标进入 widget 的回调函数
        
        参数
        =========
        :event:  来自于 tkinter,有鼠标的 x,y 坐标属性
        """
        self.cursor(event)
        self.schedule()
        
    def hidetip(self):
        """
        销毁 tooltip window
        """
        if self.tipwindow:
            self.tipwindow.destroy()
        else:
            self.tipwindow = None
          
    def leave(self, event):
        """
        鼠标离开 widget 的销毁 tooltip window
         
        参数
        =========
        :event:  来自于 tkinter,没有被使用
        """
        self.unschedule()
        self.hidetip()

下面看一个示例:

root = Tk()
lb = ttk.Label(root, text='测试 ToolTip', font=('',27))
tooltip = ToolTip(lb, "您好!")
lb.grid()
root.mainloop()

显示效果图:

图1 ToolTip 示例

更加通用的 ToolTip 见我的 GitHub: tkinter_action