Search code examples
pythontkintertooltip

How do i implement this python tkinter tooltip without overriding the button press animation


I'm using the following script for assigning and managing tooltips. It works, but with a small disadvantage. The button widgets I assign tooltips to no longer have a click down animation unless the tooltip script executes after 500ms. Any ideas? If possible, i want to keep the native button behavior at any time AND have a 500ms wait before showing a tooltip.

class ToolTip(object):
    def __init__(self, widget):
        self.widget = widget
        self.tipwindow = None
        self.id = None
        self.x = self.y = 0
    def showtip(self, text):
        self.text = text
        if self.tipwindow or not self.text: return
        x,y,cx,cy = self.widget.bbox("insert")
        x = x + self.widget.winfo_rootx() +15
        y = y + cy + self.widget.winfo_rooty() +65
        self.tipwindow = tw = Toplevel(self.widget)
        tw.wm_overrideredirect(1)
        tw.wm_geometry("+%d+%d"%(x,y))
        label = Label(tw, text=self.text, justify=LEFT,background="#ffffe0", relief=SOLID, borderwidth=1,font=("tahoma", "8", "normal"))
        label.pack(ipadx=1)
    def hidetip(self):
        tw = self.tipwindow
        self.tipwindow = None
        if tw: tw.destroy()

def createToolTip(self,widget,text):
    toolTip = self.ToolTip(widget)
    def enter(event): root.after(500,show(event))
    def show(event): toolTip.showtip(text)
    def leave(event): toolTip.hidetip()
    widget.bind('<Enter>', enter)
    widget.bind('<Leave>', leave)

Solution

  • You have a bug in your code. You have this:

    def enter(event): root.after(500,show(event))
    

    However, the argument to after should be a reference to a function, not an actual function call. Change it to this:

    def enter(event): root.after(500,show,event)
    

    What is happening is this: when you do root.after(500, show(event)), the first thing that happens is that show(event) runs before calling after. The result of that (None) is used in the after, effectively making it root.after(500, None). This causes your whole GUI sleep for half a second. While it is sleeping it is unable to respond to any events which is why you don't see the animation.