A tooltip class for Tkinter

vegaseat 7 Tallied Votes 13K Views Share

This class gives a specified Tkinter widget a tooltip that appears as the mouse is above the widget. You can improve the code by putting in a time delay.

''' tk_ToolTip_class101.py
gives a Tkinter widget a tooltip as the mouse is above the widget
tested with Python27 and Python34  by  vegaseat  09sep2014
'''

try:
    # for Python2
    import Tkinter as tk
except ImportError:
    # for Python3
    import tkinter as tk


class CreateToolTip(object):
    '''
    create a tooltip for a given widget
    '''
    def __init__(self, widget, text='widget info'):
        self.widget = widget
        self.text = text
        self.widget.bind("<Enter>", self.enter)
        self.widget.bind("<Leave>", self.close)

    def enter(self, event=None):
        x = y = 0
        x, y, cx, cy = self.widget.bbox("insert")
        x += self.widget.winfo_rootx() + 25
        y += self.widget.winfo_rooty() + 20
        # creates a toplevel window
        self.tw = tk.Toplevel(self.widget)
        # Leaves only the label and removes the app window
        self.tw.wm_overrideredirect(True)
        self.tw.wm_geometry("+%d+%d" % (x, y))
        label = tk.Label(self.tw, text=self.text, justify='left',
                       background='yellow', relief='solid', borderwidth=1,
                       font=("times", "8", "normal"))
        label.pack(ipadx=1)

    def close(self, event=None):
        if self.tw:
            self.tw.destroy()

# testing ...
if __name__ == '__main__':
    root = tk.Tk()

    btn1 = tk.Button(root, text="button 1")
    btn1.pack(padx=10, pady=5)
    button1_ttp = CreateToolTip(btn1, "mouse is over button 1")

    btn2 = tk.Button(root, text="button 2")
    btn2.pack(padx=10, pady=5)
    button2_ttp = CreateToolTip(btn2, "mouse is over button 2")

    root.mainloop()

Dani AI

Generated

Looking for a pure-Tkinter alternative to Tix that works the same on Windows, macOS, and Linux? Here is a minimal tooltip helper that adds a configurable delay, follows the cursor, and reliably cancels on leave or click. It avoids external dependencies, which is handy given Tix’s inconsistent availability on some Linux distros.

import tkinter as tk
from tkinter import ttk

class Tooltip:
    def __init__(self, widget, text, delay=500):
        self.widget, self.text, self.delay = widget, text, delay
        self._after_id = None
        self._tip = None
        widget.bind("<Enter>", self._schedule)
        widget.bind("<Leave>", self._hide)
        widget.bind("<ButtonPress>", self._hide)
        widget.bind("<Motion>", self._move)

    def _schedule(self, _=None):
        self._cancel()
        self._after_id = self.widget.after(self.delay, self._show)

    def _show(self):
        if self._tip:
            return
        self._tip = tk.Toplevel(self.widget)
        self._tip.wm_overrideredirect(True)
        self._tip.wm_attributes("-topmost", True)
        tk.Label(self._tip, text=self.text, bg="#ffffe0",
                 relief="solid", bd=1, justify="left").pack(ipadx=4, ipady=2)
        self._move()

    def _move(self, event=None):
        if not self._tip:
            return
        x = (event.x_root + 12) if event else self.widget.winfo_rootx() + 12
        y = (event.y_root + 8) if event else self.widget.winfo_rooty() + self.widget.winfo_height() + 4
        self._tip.geometry(f"+{x}+{y}")

    def _hide(self, _=None):
        self._cancel()
        if self._tip:
            self._tip.destroy()
            self._tip = None

    def _cancel(self):
        if self._after_id:
            self.widget.after_cancel(self._after_id)
            self._after_id = None

# Example:
# btn = ttk.Button(root, text="Hover me")
# Tooltip(btn, "Click to submit", delay=700)

If you do want tkinter.tix on Ubuntu, you typically need both python3-tk and the system Tix library (tix) installed; without the latter, imports will fail. Tix is considered legacy, so prefer pure Tk when possible. See tkinter docs and tkinter.tix docs for details.

theduke540 0 Newbie Poster

This is excellent! Just what I was looking for. I tried Tix, but had no luck. This is simple and it works. I had to sign up just to show my thanks!

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

Just to mention it ...

''' tix_Balloon102.py
Tkinter extension module tix comes with Python27 and Python3+
tix has addtional widgets like ...
tix.Balloon (acts like a tooltip)
'''

try:
    # Python2
    import Tix as tix
except ImportError:
    # Python3
    import tkinter.tix as tix

root = tix.Tk()

def hello():
    label['text'] = 'Hello World'
    #label.config(text='Hello World')

def bye():
    label['text'] = 'Bye Cruel World'

label = tix.Label(root, width=40, relief=tix.SUNKEN, bd=1)
btn1 = tix.Button(root, text="Hello", command=hello)
btn2 = tix.Button(root, text="Bye", command=bye)

# create balloon (tooltip) instance
balloon = tix.Balloon(root)

# bind balloon to buttons
balloon.bind_widget(btn1, balloonmsg='Click to show Hallo')
balloon.bind_widget(btn2, balloonmsg='Click to show Bye')

# layout, stack vertically
label.pack()
btn1.pack(pady=8)
btn2.pack(pady=8)

root.mainloop()
fonzali 0 Light Poster

the code works fine on my windows machine but on ubuntu 14.04 it says it can not find ' tix ' . do I need to install it separately ?

Marc_10 0 Newbie Poster

In the 1st class you can add in line 38:
label.after(1000, self.close)
to disappear the label after 1 sec

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.