Search code examples
pythontkintertransparencytkinter-canvas

Tkinter create_image() retains PNG transparency but Button(image) does not


TkVersion = 8.6, Python version 3.7.3

Im trying to create a button in python with tkinter using a PNG image. The transparent corners of the image are transparent depending on which widget I use. It seems canvas.create_image is the only widget retaining the transparency.

First I added the image on a canvas using create_image(0,0, image=button) and it works fine - the rounded corners are transparent.

But then when I try to implement it as an actual button using Button() and create_window() widgets, the corners are filled with white.

button = ImageTk.PhotoImage(file="button.png")

canvas = tk.Canvas(width=200, heigh=200, borderwidth=0, highlightthickness=0)
canvas.grid()
canvas.create_rectangle(0,0,199,199, fill="blue")

canvas.create_image(0,0, image=button, anchor="nw")

works[]

button = ImageTk.PhotoImage(file="button.png")

canvas = tk.Canvas(width=200, heigh=200, borderwidth=0, highlightthickness=0)
canvas.grid()
canvas.create_rectangle(0,0,199,199, fill="blue")

buttonWidget = tk.Button(root, image=button)
canvas.create_window(0,0, window=buttonWidget, anchor="nw")

doesnt work

How can I make the PNG button corners transparent?

Here is also the button image: button


Solution

  • You can make your own custom button class inherited from canvas and use it just like you use Button(). I made one for you hopefully you find it helpful.

    Custom Button Class:

    Save this class in a separate file as imgbutton.py and then import it to your main file. Also make sure it is in the same directory as the main file is in. Or you can just keep it on the top of the main file after your imports.

    import tkinter as tk
    
    class Imgbutton(tk.Canvas):
    
        def __init__(self, master=None, image=None, command=None, **kw):
    
            # Declared style to keep a reference to the original relief
            style = kw.get("relief", "groove")        
    
            if not kw.get('width') and image:
                kw['width'] = image.width()
            else: kw['width'] = 50
    
            if not kw.get('height') and image:
                kw['height'] = image.height()
            else: kw['height'] = 24
    
            kw['relief'] = style
            kw['borderwidth'] = kw.get('borderwidth', 2)
            kw['highlightthickness'] = kw.get('highlightthickness',0)
    
            super(Imgbutton, self).__init__(master=master, **kw)
    
            self.set_img = self.create_image(kw['borderwidth'], kw['borderwidth'], 
                    anchor='nw', image=image)
    
            self.bind_class( self, '<Button-1>', 
                        lambda _: self.config(relief='sunken'), add="+")
    
            # Used the relief reference (style) to change back to original relief.
            self.bind_class( self, '<ButtonRelease-1>', 
                        lambda _: self.config(relief=style), add='+')
    
            self.bind_class( self, '<Button-1>', 
                        lambda _: command() if command else None, add="+")
    

    Here is an Example how to use it

    import tkinter as tk
    from imgbutton import Imgbutton    # Import the custom button class
    
    root = tk.Tk()
    root['bg'] = 'blue'
    
    but_img = tk.PhotoImage(file='button.png')
    
    but = Imgbutton(root, image=but_img, bg='blue', 
                command=lambda: print("Button Image"))
    but.pack(pady=10)
    
    root.mainloop()