Перетаскиваемая этикетка Tkinter с прозрачным изображением, все еще покрывающим изображение из родительского холста

Я работаю над добавлением перетаскиваемых надписей поверх фонового изображения, где надписи представляют собой изображения с прозрачным фоном. Сами изображения, используемые для метки, являются прозрачными, но сама метка не является прозрачной по отношению к родительскому холсту. Поскольку метки можно перетаскивать, я не могу легко использовать родительское изображение для метки и вставить прозрачное изображение сверху.

Это изображение моей проблемы

Дракон представляет собой перетаскиваемый ярлык с прозрачным фоном, но вы видите, что сам ярлык не является прозрачным и покрывает изображение холста.

Само изображение дракона имеет прозрачный фон, так как обычный фон синий, поэтому я знаю, что проблема заключается в прозрачности метки.

Желаемым поведением было бы обеспечение прозрачности метки, поэтому, когда изображение на метке прозрачное, метка должна отображаться на изображении ниже.

Вот минимальный пример:

from PIL import Image, ImageTk
import numpy as np
import tkinter as tk

#Creates a blue square with a transparent border
blue_square_transparent_border = [[[0,0,0,0]]*100]*10 + [[[0,0,0,0]]*30 + [[0,0,255,255]]*40 + [[0,0,0,0]]*30]*40 + [[[0,0,0,0]]*100]*10
blue_square_transparent_border = np.array(blue_square_transparent_border, dtype='uint8')
#convert numpy array to PIL image
pil_image = Image.fromarray(blue_square_transparent_border)

root = tk.Tk()
root.configure(background='red')
#convert PIL image to tkinter image
tk_image = ImageTk.PhotoImage(pil_image)
#create label
image_label = tk.Label(root, image=tk_image)
image_label.pack()
root.mainloop()

Я хотел бы видеть синий квадрат на красном фоне без рамки. В приведенном выше примере граница серого цвета появляется, так как это метка, видимая через прозрачное изображение; это легко увидеть, если вы измените размер окна. Я подозреваю, что если бы этикетка была прозрачной, это решило бы мои проблемы.

Любая помощь будет отличной, спасибо!

1 ответ

Решение

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

Идея не в том, чтобы использовать ярлыки, а create_image метод Canvas, Сначала отобразите фоновое изображение с помощью canvas.create_image(0, 0, image=background_image, anchor='nw'), затем отобразите все перетаскиваемые изображения с тегом "перетаскиваемый": canvas.create_image(x, y, image=draggable_image, anchor='nw', tag='draggable'), Наконец, свяжите тег "перетаскиваемый" с событиями мыши.

Вот пример:

import tkinter as tk
import numpy as np
from PIL import Image, ImageTk

# drag callbacks
dragged_item = None
current_coords = 0, 0

def start_drag(event):
    global current_coords
    global dragged_item
    result = canvas.find_withtag('current')
    if result:
        dragged_item = result[0]
        current_coords = canvas.canvasx(event.x), canvas.canvasy(event.y)
    else:
        dragged_item = None

def stop_drag(event):
    dragged_item = None

def drag(event):
    global current_coords
    xc, yc = canvas.canvasx(event.x), canvas.canvasy(event.y)
    dx, dy = xc - current_coords[0], yc - current_coords[1]
    current_coords = xc, yc
    canvas.move(dragged_item, dx, dy)


#Create pictures
blue_square_transparent_border = [[[0,0,0,0]]*100]*10 + [[[0,0,0,0]]*30 + [[0,0,255,255]]*40 + [[0,0,0,0]]*30]*40 + [[[0,0,0,0]]*100]*10
blue_square_transparent_border = np.array(blue_square_transparent_border, dtype='uint8')
pil_image = Image.fromarray(blue_square_transparent_border)

background_data = np.zeros((200, 400, 4))
background_data[:, :, 0] = 255 * np.ones((200, 400))
background_data[:, :, 3] = 255 * np.ones((200, 400))
background_data = np.array(background_data, dtype='uint8')
pil_image_bg = Image.fromarray(background_data)

# create GUI
root = tk.Tk()
background_image = ImageTk.PhotoImage(pil_image_bg)
tk_image = ImageTk.PhotoImage(pil_image)

canvas = tk.Canvas(root, width=400, height=200)
canvas.pack()
# bind 'draggable' tag to mouse events
canvas.tag_bind('draggable', '<ButtonPress-1>', start_drag)
canvas.tag_bind('draggable', '<ButtonRelease-1>', stop_drag)
canvas.tag_bind('draggable', '<B1-Motion>', drag)
# display pictures
canvas.create_image(0, 0, image=background_image, anchor='nw')
canvas.create_image(0, 0, image=tk_image, anchor='nw', tag='draggable')

root.mainloop()
Другие вопросы по тегам