menu

Questions & Answers

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

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 Projects\main.py", line 10, in <module>
    ToolTip(button, msg="A message", delay=0, follow=True,
  File "D:\Python311\Lib\site-packages\tktooltip\tooltip.py", line 83, in __init__ 
    self.widget.bind("<Enter>", self.on_enter, add="+")
  File "D:\Python311\Lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 544, in bind
    self._text_label.bind(sequence, command, add=True)
    ^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'bind'
Comments:
2023-01-24 00:30:06
have you tried to reverse the order of the ToolTip() and button.pack() calls?
2023-01-24 00:30:06
Please, show the full traceback you get
2023-01-24 00:30:06
This looks like a bug or poorly designed feature of CTkButton and/or CTkImage. The code works fine with a normal tkinter button.
2023-01-24 00:30:06
@father_goose it's no use.
2023-01-24 00:30:06
@buran I added as you requested.
Answers(1) :

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)
...
Comments:
2023-01-24 00:30:06
Thanks, I'll notify the dev about this. But as I stated in the post I don't wanna set text = " ", because the shape gets distorted.
2023-01-24 00:30:06
Then you need to change the source of ctk_button.py of customtkinter. Or override the bind() by creating custom CTkButton class.