How to add a tooltip to a customtkinter image (CTkImage)?

Question:

I’m using tkinter-tooltip and when I try to add a tooltip to a button consisting of only an image, it says "NoneType' object has no attribute 'bind'". It works if I do text=" " but I don’t wanna make the text a space or anything, because its shape gets distorted. I just want to add a tooltip to image, is there any way to override this?

import customtkinter
from PIL import Image
from tktooltip import ToolTip

root = customtkinter.CTk()

icon = customtkinter.CTkImage(dark_image=Image.open("icon.png"))
button = customtkinter.CTkButton(master=root, width=10, height=10, text="", image=icon)
button.pack(pady=20, padx=20)

ToolTip(button, msg="A message", delay=0, follow=True,
        parent_kwargs={"bg": "black", "padx": 3, "pady": 3},
        fg="white", bg="orange", padx=7, pady=7)

root.mainloop()
Traceback (most recent call last):
  File "d:Python Projectsmain.py", line 10, in <module>
    ToolTip(button, msg="A message", delay=0, follow=True,
  File "D:Python311Libsite-packagestktooltiptooltip.py", line 83, in __init__ 
    self.widget.bind("<Enter>", self.on_enter, add="+")
  File "D:Python311Libsite-packagescustomtkinterwindowswidgetsctk_button.py", line 544, in bind
    self._text_label.bind(sequence, command, add=True)
    ^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'bind'
Asked By: duruburak

||

Answers:

As Bryan said, it is a bug in customtkinter that when text option is an empty string, the internal label self._text_label will not be created and so it is None. You can overcome this by setting text=" " instead.

Also it is better not to set delay=0 in ToolTip(...) as it will make the tooltip not showing sometimes. Just give delay a very small value like 0.01 for example.

import customtkinter
from PIL import Image
from tktooltip import ToolTip

root = customtkinter.CTk()

icon = customtkinter.CTkImage(dark_image=Image.open("icon.png"))
# set text=" "
button = customtkinter.CTkButton(master=root, width=10, height=10, text=" ", image=icon)
button.pack(pady=20, padx=20)

# set delay=0.01
ToolTip(button, msg="A message", delay=0.01, follow=True,
        parent_kwargs={"bg": "black", "padx": 3, "pady": 3},
        fg="white", bg="orange", padx=7, pady=7)

root.mainloop()

Another option is to create a custom CTkButton class and override the bind() function:

class MyButton(customtkinter.CTkButton):
    def bind(self, sequence=None, command=None, add=True):
        if not (add == "+" or add is True):
            raise ValueError("'add' argument can only be '+' or True to preserve internal callbacks")
        self._canvas.bind(sequence, command, add=True)
        if self._text_label:
            self._text_label.bind(sequence, command, add=True)
        if self._image_label:
            self._image_label.bind(sequence, command, add=True)
...
button = MyButton(master=root, width=20, height=20, text="", image=icon)
...
Answered By: acw1668