Как сделать поясняющий текст справа от мышки при попадании в круги?

У меня есть программа, ниже будет код. Которая при наведении мышью на круги должна выводить около мыши поясняющий текст, как это можно реализовать? Код:

from tkinter import *
#from PIL import Image, ImageTk


#from idlelib.tooltip import Hovertip

root = Tk()
x = None
y = None

#b1 = Button(text='button with tooltip')
#b1.pack()
#Hovertip(b1, "абракадабра", hover_delay=100)

def getorigin(event):
    global x, y
      
    x = event.x                                                             # !!!
    y = event.y                                                             # !!!
      

    if (0 <= x <= 100) and (0 <= y <= 100):                                 # !!!
        print(f'Вы попали в квадрат (0, 0) - (100, 100). X = {x}, Y = {y}')

    if (200 <= x <= 300) and (0 <= y <= 100):                                 # !!!
        print(f'Вы попали в квадрат (0, 0) - (100, 100). X = {x}, Y = {y}')
          
root.bind("<Motion>",getorigin)

#Добавим изображение
canvas = Canvas(root, height=800, width=800)
#image = Image.open("bizon.jpg")
#photo = ImageTk.PhotoImage(image)
#image = canvas.create_image(0, 0, image=photo, anchor='nw')
shar1=canvas.create_oval(0, 0, 100, 100, outline="yellow", fill="#125B50", width=2)
shar2=canvas.create_oval(200, 0, 300, 100, outline="yellow", fill="#125B50", width=2)


    
canvas.pack()
root.mainloop()

Ответы (1 шт):

Автор решения: insolor

Отображение подсказки через create_text при попадании мыши в ограничивающий прямоугольник нужной фигуры:

from tkinter import *
from PIL import Image, ImageTk

root = Tk()


tooltip = None


def create_tooltip(x, y, text):
    global tooltip
    tooltip = canvas.create_text(x, y, text=text, anchor=NW)


def delete_tooltip():
    global tooltip
    canvas.delete(tooltip)
    tooltip = None


def on_move(event):
    x1, y1, x2, y2 = canvas.bbox(oval)  # Получаем координаты ограничивающего прямоугольника для овала
    if (x1 <= event.x <= x2) and (y1 <= event.y <= y2):
        if tooltip is None:
            create_tooltip(event.x + 10, event.y + 10, "Наведено на овал")
        else:
            canvas.moveto(tooltip, event.x + 10, event.y + 10)
    else:
        delete_tooltip()


def on_leave(event):
    delete_tooltip()

          
root.bind("<Motion>", on_move)  # Событие движения мыши по холсту
root.bind("<Leave>", on_leave)  # Событие перемещения мыши за пределы холста

canvas = Canvas(root, height=800, width=800)

oval=canvas.create_oval(0, 0, 100, 100, outline="yellow", fill="#125B50", width=2)
canvas.pack()

root.mainloop()

Подсказка просто текстом

Для подсказки с фоном и рамкой можно использовать create_window с Label внутри вместо create_text:

def create_tooltip(x, y, text):
    global tooltip
    label = Label(text=text, justify=LEFT, background="#ffffe0", relief=SOLID, borderwidth=1)
    tooltip = canvas.create_window(x, y, window=label, anchor=NW)

Подсказка с фоном и рамкой

Дополнительно, более строгая проверка попадания указателя внутрь эллипса через уравнение эллипса (тогда подсказка будет отображаться только внутри эллипса, но не внутри всего ограничивающего прямоугольника эллипса):

def on_move(event):
    x1, y1, x2, y2 = canvas.bbox(oval)  # Получаем координаты ограничивающего прямоугольника для эллипса

    # Координаты центра эллипса
    xc = (x1 + x2) / 2
    yc = (y1 + y2) / 2

    # Вычисляем полуоси эллипса (сразу возводим в квадрат, потом подставляем в уравнение)
    a2 = (xc - x1) ** 2
    b2 = (yc - y1) ** 2

    # Координаты мыши относительно центра эллипса
    x = event.x - xc
    y = event.y - yc

    if (x ** 2 / a2 + y ** 2 / b2) <= 1:
        if tooltip is None:
            create_tooltip(event.x + 10, event.y + 10, "Наведено на овал")
        else:
            canvas.moveto(tooltip, event.x + 10, event.y + 10)
    else:
        delete_tooltip()

Код с проверкой на попадание в один из нескольких эллипсов:

from tkinter import *
from PIL import Image, ImageTk

root = Tk()


tooltip = None


def create_tooltip(x, y, text):
    global tooltip
    label = Label(text=text, justify=LEFT, background="#ffffe0", relief=SOLID, borderwidth=1)
    tooltip = canvas.create_window(x, y, window=label, anchor=NW)


def delete_tooltip():
    global tooltip
    canvas.delete(tooltip)
    tooltip = None


def in_ellipse(x, y, ellipse):
    x1, y1, x2, y2 = canvas.bbox(ellipse)

    # Координаты центра эллипса
    xc = (x1 + x2) / 2
    yc = (y1 + y2) / 2

    # Вычисляем полуоси эллипса (сразу возводим в квадрат, потом подставляем в уравнение)
    a2 = (xc - x1) ** 2
    b2 = (yc - y1) ** 2

    # Координаты мыши относительно центра эллипса
    x = x - xc
    y = y - yc

    return (x ** 2 / a2 + y ** 2 / b2) <= 1


last_ellipse = None


def on_move(event):
    global last_ellipse
    for ellipse, name in ellipses.items():
        if in_ellipse(event.x, event.y, ellipse):
            if ellipse != last_ellipse:
                delete_tooltip()
                last_ellipse = ellipse

            if tooltip is None:
                create_tooltip(event.x + 10, event.y + 10, f"Наведено на {name}")
            else:
                canvas.moveto(tooltip, event.x + 10, event.y + 10)
            
            break
    else:
        # Ни на что не наведено
        last_ellipse = None
        delete_tooltip()


def on_leave(event):
    global last_ellipse
    last_ellipse = None
    delete_tooltip()

          
root.bind("<Motion>", on_move)  # Событие движения мыши по холсту
root.bind("<Leave>", on_leave)  # Событие перемещения мыши за пределы холста

canvas = Canvas(root, height=800, width=800)
canvas.pack()

shar1=canvas.create_oval(0, 0, 100, 100, outline="yellow", fill="#125B50", width=2)
shar2=canvas.create_oval(200, 0, 300, 100, outline="yellow", fill="#125B50", width=2)

ellipses = {
    shar1: "Шар 1",
    shar2: "Шар 2",
}

root.mainloop()

Наведено на Шар 1

Наведено на Шар 2

→ Ссылка