0

I am having a problem in making a login image to a button. I have succeeded in making the image with a transparent background, but I can't succeed to make the button with transparent background.

I attached a screenshot that shows what I mean. The upper 'login' is a image (with transparent background), the lower is Login button but there is a white background around it. I want to make a button with transparent background.

self.login_image = Image.open('images/LoginButton.png')
self.login_image = ImageTk.PhotoImage(self.login_image)
self.main_screen_canvas.create_image(700, 300, image=self.login_image)

self.login_button = Button(self.main_screen_canvas, borderwidth=0, image=self.login_image)

self.login_button.place(x=300,y=400)

What should I do?

enter image description here

BackgroundImage LoginButtonImage

OmerC
  • 29
  • 3
  • Did you read the comments to [this question](https://stackoverflow.com/q/71036589/16775594), and visit the links they provided? In other words, have you looked at [this question](https://stackoverflow.com/q/10461045/16775594)? You can look at [one of its answers](https://stackoverflow.com/a/39271423/16775594), but that answer seems to only work on Windows. According to [the other answer](https://stackoverflow.com/a/10461175/16775594), transparent backgrounds aren't supported (I guess on systems other than Windows). – Sylvester Kruin Feb 12 '22 at 18:42
  • 1
    If the `LoginButton.png` image has a transparent background, then you get the effect you want by placing the background image in one `Canvas.create_image()` object and putting the login button image in another somewhere on top of it. You can see an example of doing that in this [answer of mine](https://stackoverflow.com/questions/70996098/tkinter-button-over-transparent-background/71011331#71011331). – martineau Feb 12 '22 at 19:03
  • OmerC if you want that the user you reply to get a notify use *@username* otherwise you may want forever for @martineau – Thingamabobs Feb 12 '22 at 19:16
  • @martineau Do you mean to put the button underneath the image? – – OmerC Feb 12 '22 at 19:18
  • No. I mean put the background image in one Canvas image object and put the button image in another somewhere on *top* of that. Look at the answer I linked. – martineau Feb 12 '22 at 19:19
  • OmerC: If you can't figure it out, [edit] your question and post links to the background and button images, and I'll can show you what I mean. – martineau Feb 12 '22 at 19:47
  • @martineau Thank you so much. Kind of new at python and never faced with tkinter. I am trying to do this from like 7 hours ago ^^ – OmerC Feb 12 '22 at 19:55

1 Answers1

1

Here's how to do what I was suggesting in the comment which uses the technique shown in another answer of mine to simulate a tkinter Button on a Canvas that has a transparent image placed on it (instead of text).

One issue I ran into was that fact that your 2421 × 1210 pixel background image was larger than my screen. To deal with it I added a fitrect() helper function to determine a new smaller size for it that would fit. I wrote it a long time ago, but have found it handy to have around many times (like now). Note that in the code ll and ur refer to the lower-left and upper-right corners of the rectangles involved.

Here's the resulting code:

from PIL import Image, ImageTk
import tkinter as tk

class CanvasButton:
    """ Create left 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_source, command, state=tk.NORMAL):
        self.canvas = canvas

        if isinstance(image_source, str):
            self.btn_image = tk.PhotoImage(file=image_source)
        else:
            self.btn_image = image_source

        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)


def fitrect(r1_ll_x, r1_ll_y, r1_ur_x, r1_ur_y, r2_ll_x, r2_ll_y, r2_ur_x, r2_ur_y):
    """ Find the largest rectangle that will fit within rectangle r2 that has
        rectangle r1's aspect ratio.

        Note: Either the width or height of the resulting rect will be
              identical to the corresponding dimension of rect r2.
    """
    # Calculate aspect ratios of rects r1 and r2.
    deltax1, deltay1 = (r1_ur_x - r1_ll_x), (r1_ur_y - r1_ll_y)
    deltax2, deltay2 = (r2_ur_x - r2_ll_x), (r2_ur_y - r2_ll_y)
    aspect1, aspect2 = (deltay1 / deltax1), (deltay2 / deltax2)

    # Compute size of resulting rect depending on which aspect ratio is bigger.
    if aspect1 > aspect2:
        result_ll_y, result_ur_y = r2_ll_y, r2_ur_y
        delta = deltay2 / aspect1
        result_ll_x = r2_ll_x + (deltax2 - delta) / 2.0
        result_ur_x = result_ll_x + delta
    else:
        result_ll_x, result_ur_x = r2_ll_x, r2_ur_x
        delta = deltax2 * aspect1
        result_ll_y = r2_ll_y + (deltay2 - delta) / 2.0
        result_ur_y = result_ll_y + delta

    return result_ll_x, result_ll_y, result_ur_x, result_ur_y

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


background_image_path = 'background_image.jpg'
button_image_path = 'button_image.png'

root = tk.Tk()
root.update_idletasks()
background_img = Image.open(background_image_path)  # Must use PIL for JPG images.

scrnwidth, scrnheight = root.winfo_screenwidth(), root.winfo_screenheight()
bgrdwidth, bgrdheight = background_img.size
border_width, border_height = 20, 20  # Allow room for window's decorations.

# Determine a background image size that will fit on screen with a border.
bgr_ll_x, bgr_ll_y, bgr_ur_x, bgr_ur_y = fitrect(
                                0, 0, bgrdwidth, bgrdheight,
                                0, 0, scrnwidth-border_width, scrnheight-border_height)
bgr_width, bgr_height = int(bgr_ur_x-bgr_ll_x), int(bgr_ur_y-bgr_ll_y)

# Resize background image to calculated size.
background_img = ImageTk.PhotoImage(background_img.resize((bgr_width, bgr_height)))

# Create Canvas same size as fitted background image.
canvas = tk.Canvas(root, bd=0, highlightthickness=0, width=bgr_width, height=bgr_height)
canvas.pack(fill=tk.BOTH)

# Put background image on Canvas.
background = canvas.create_image(0, 0, anchor='nw', image=background_img)

# Put CanvasButton on Canvas centered at the bottom.
button_img = tk.PhotoImage(file=button_image_path)
btn_x, btn_y = (bgr_width/2), (bgr_height-button_img.height())

canvas_btn1 = CanvasButton(canvas, btn_x, btn_y, button_img, btn_clicked)

root.mainloop()

And here's the result of running it:

screenshot of background image with a button on it with a transparent background

martineau
  • 119,623
  • 25
  • 170
  • 301
  • wow!! That was way to complicated than I thought it will be. First of I forgot that I need to resize the image to be fitted to every screen(not just mine). Second of all, thank you so much, that seems great. Much appreciation! – OmerC Feb 13 '22 at 11:10