0

I am trying to understand how to apply a button to a transparent background while keeping its shape. When I generate the code below, there is a gray background around the border that appears, and it also looks like it loses its shape.

Colors Used

Sidebar: #2E3A4B at 53%

Button: #2C2F33 at 100%

from tkinter import *


def btn_clicked():
    """ Prints to console a message every time the button is clicked """
    print("Button Clicked")


root = Tk()

# Configures the frame, and sets up the canvas
root.geometry("1440x1024")
root.configure(bg="#ffffff")
canvas = Canvas(root, bg="#ffffff", height=1024, width=1440, bd=0, highlightthickness=0, relief="ridge")
canvas.place(x=0, y=0)

background_img = PhotoImage(file=f"background.png")
background = canvas.create_image(719.5, 512.5, image=background_img)

img0 = PhotoImage(file=f"img0.png")
alarm_button = Button(image=img0, borderwidth=0, highlightthickness=0, command=btn_clicked, relief="flat")

alarm_button.place(x=9, y=119, width=90, height=90)

root.resizable(False, False)
root.mainloop()

Required Images

enter image description here enter image description here

How it looks:

enter image description here

How it should look:

enter image description here

yet-it-compiles
  • 108
  • 1
  • 10
  • 1
    No, I don't see it getting lighter. – martineau Feb 05 '22 at 09:26
  • Thanks @martineau for pointing out it may have no been a good example image. I just retook one placing more buttons to show what I meant. – yet-it-compiles Feb 05 '22 at 16:30
  • 1
    Sorry, they all look the same to me. – martineau Feb 05 '22 at 16:32
  • No @martineau, it's my fault. I just updated the image with how It should look. If you notice with the *problem image* you can see the fixed colors behind it making the squares, then if you notice how it *should look* it is clean, and the buttons can be placed over the transparent issue no problem if this makes sense? The side bars color is: 2E3A4B with a transparency of 53% – yet-it-compiles Feb 05 '22 at 16:42
  • 1
    What is the "other object of a fixed color" and where are you putting it behind the alarm button? – martineau Feb 05 '22 at 16:55
  • I just updated everything above to be more clear @martineau, I realized the wording was confusing. I am just trying to figure out how to get the image to generate right. I have tried importing them as .gif but that didn't seem to work either. – yet-it-compiles Feb 06 '22 at 03:40
  • 1
    OK, I now understand what you're asking and was able to reproduce the problem. Unfortunately I don't think you can do what you want with `tkinter`. – martineau Feb 06 '22 at 07:33
  • That's the notion I was getting too @martineau, I ran across this post: https://stackoverflow.com/questions/29857757/transparent-backgrounds-on-buttons-in-tkinter and it said there is a way, I just wasn't able to get it working because the code is a bit different, but still using Tkinter. Do you have any recommendations from viewing this? – yet-it-compiles Feb 06 '22 at 16:31
  • 1
    Which *answer* to that linked question are you referring to? – martineau Feb 06 '22 at 17:11
  • The last one @martineau – yet-it-compiles Feb 06 '22 at 18:33
  • 1
    "last one" is meaningless since the order they get displayed in can vary. Either provide a link directly to the answer or specify the answer's author's user name. – martineau Feb 06 '22 at 18:46
  • 1
    @martineau answer from Deesram : https://stackoverflow.com/a/70024912/16780427 – yet-it-compiles Feb 06 '22 at 18:51
  • 1
    OK. It looks like *might* work to some degree — I'll play around with it and get back to you. – martineau Feb 06 '22 at 18:58

1 Answers1

2

Good news! I was able to get that answer to a related question you found to work. To make it easier to reuse I've converted it into a formal class and added a couple of methods. In addition I made it flash the image off and back on when it's clicked to give the user some visual feedback like "real" tkinter Buttons do.

Note that it responds to mouse button <ButtonRelease-1> events. That's a better choice in most cases than the <Button-1> event because if the user accidentally presses the button, they can move the mouse off the widget image to avoid setting off the event.

Turns out that using the PIL module was unnecessary. Here's the code:

import tkinter as tk  # PEP 8 recommends avoiding `import *`.


class CanvasButton:
    """ Create leftmost mouse button clickable canvas image object.

    The x, y coordinates are relative to the top-left corner of the canvas.
    """
    flash_delay = 100  # Milliseconds.

    def __init__(self, canvas, x, y, image_path, command, state=tk.NORMAL):
        self.canvas = canvas
        self.btn_image = tk.PhotoImage(file=image_path)
        self.canvas_btn_img_obj = canvas.create_image(x, y, anchor='nw', state=state,
                                                      image=self.btn_image)
        canvas.tag_bind(self.canvas_btn_img_obj, "<ButtonRelease-1>",
                        lambda event: (self.flash(), command()))
    def flash(self):
        self.set_state(tk.HIDDEN)
        self.canvas.after(self.flash_delay, self.set_state, tk.NORMAL)

    def set_state(self, state):
        """ Change canvas button image's state.

        Normally, image objects are created in state tk.NORMAL. Use value
        tk.DISABLED to make it unresponsive to the mouse, or use tk.HIDDEN to
        make it invisible.
        """
        self.canvas.itemconfigure(self.canvas_btn_img_obj, state=state)


BGR_IMG_PATH = "sunset_background.png"
BUTTON_IMG_PATH = "alarm_button.png"

def btn_clicked():
    """ Prints to console a message every time the button is clicked """
    print("Button Clicked")

root = tk.Tk()

background_img = tk.PhotoImage(file=BGR_IMG_PATH)
bgr_width, bgr_height = background_img.width(), background_img.height()

root.geometry(f'{bgr_width}x{bgr_height}')
root.title("TKinter button over transparent background")
root.configure(bg="white")

canvas = tk.Canvas(root, bg="white", height=bgr_height, width=bgr_width, bd=0,
                   highlightthickness=0, relief="ridge")
canvas.place(x=0, y=0)

background = canvas.create_image(0, 0, anchor='nw', image=background_img)

canvas_btn1 = CanvasButton(canvas, 0, 128, BUTTON_IMG_PATH, btn_clicked)
canvas_btn2 = CanvasButton(canvas, 0, 256, BUTTON_IMG_PATH, btn_clicked)

root.resizable(False, False)
root.mainloop()

Screenshot of the result:

Screenshot of the result

Close up:

screenshot of close up

martineau
  • 119,623
  • 25
  • 170
  • 301
  • …I *did* notice however that you're not using [f-strings](https://docs.python.org/3.8/whatsnew/3.8.html#f-strings-support-for-self-documenting-expressions-and-debugging) correctly (or doing so unnecessarily) though. They don't do anything unless there are `{}` brackets in the string that contain a variable name or expression. – martineau Feb 08 '22 at 03:16