Can't properly set an image as canvas background in tkinter - python

I want my Tkinter window to have four buttons, each with its own background image, disposed as a 2x2 grid. I tried using frames but you can't set an image as frame background so I had to switch to Canvas. This is the code for one of the four blocks.
from tkinter import *
from PIL import ImageTk, Image
root = Tk()
root.geometry("500x200")
root.wm_title("KnowYourArt")
styles_bg = ImageTk.PhotoImage(Image.open("images/styles_bg.png"))
canvas_styles = Canvas(root)
bg = canvas_styles.create_image(100, 100, image=styles_bg)
width = 4
height = 2
Button(canvas_styles, text="Styles", width=width, height=height).pack(side=TOP)
Label(canvas_styles, text="Gain info about styles").pack(side=BOTTOM)
canvas_styles.grid(row=0, column=0)
This is the output I get:
In my intentions, the background image dimensions should cover both the button and the label, and the image's dimensions should be independent from the dimensions of the widgets. Instead, I obtain a canvas where the height of the BG image is the same as the height of the button, and the width is the same as the label's width. I tried many alternative possibilities, including setting a width and height for the canvas, and none of them properly worked. What am I doing wrong?

I managed to find a solution. Here is the code:
from tkinter import *
from PIL import ImageTk, Image
width = 4
height = 1
def add_canvas(frame, img, x, y, text):
c = Canvas(frame, width=300, height=300)
c.focus()
c.pack(fill=BOTH, expand=True)
bg = c.create_image(x, y, image=img)
btn = Button(frame, text="Go!", width=width, height=height)
c.create_text(150, 190, text=text, font=('Helvetica', 15), fill='white')
c.create_window(100, 200, anchor="nw", window=btn)
return c
root = Tk()
root.geometry("600x600")
root.wm_title("Title")
f_1 = Frame(root)
f_2 = Frame(root)
f_3 = Frame(root)
f_4 = Frame(root)
bg1 = ImageTk.PhotoImage(Image.open("images/im1.png"))
bg2 = ImageTk.PhotoImage(Image.open("images/im2.png"))
bg3 = ImageTk.PhotoImage(Image.open("images/im3.png"))
bg4 = ImageTk.PhotoImage(Image.open("images/im4.jpg"))
canvas_1 = add_canvas(f_1, bg1, 0, 0, "foo")
canvas_2 = add_canvas(f_2, bg2, 240, 240, "foo")
canvas_3 = add_canvas(f_3, bg3, 120, 120, "foo")
canvas_4 = add_canvas(f_4, bg4, 100, 100, "foo")
f_1.grid(row=0, column=0)
f_2.grid(row=0, column=1)
f_3.grid(row=1, column=0)
f_4.grid(row=1, column=1)
And here's the output

Related

create a scrollbar on entry with cavnas, python tkinter

I'm trying to put a scrollbar on entry that created on canvas..
I've tried this code
from tkinter import *
root = Tk()
root.geometry('400x600')
root.resizable(0,0)
page = Canvas(root, width=400, height=600, bd=0, highlightthickness=0,scrollregion=(0,0,500,500))
MyImage1 = PhotoImage(file='Study With4.png')
CanvasImage = page.create_image(0,0,image= MyImage1, anchor='nw')
entry =Text(page,height=29,width =46,wrap=WORD,bg='#F8F8F8')
scroll = Scrollbar(entry, orient=VERTICAL)
scroll.pack(side=RIGHT, fill=Y)
scroll.config(command=page.yview)
page.config(yscrollcommand=scroll.set)
page.create_window(200,285, window=entry)
page.pack()
mainloop()
but it doesn't work and I don't know where is the problem.
I've made minimal changes to your code, the biggest is creating a Frame called "label"
to contain Text and Scrollbar then inserting that into Canvas window.
Your scroll object was not defined properly with confusion around page and entry objects.
from tkinter import *
root = Tk()
root.geometry('500x600')
root.resizable(0,0)
page = Canvas(
root, width = 500, height = 600, bd = 0,
highlightthickness = 0,scrollregion = (0,0,1000,1000))
page.pack(side = LEFT, fill = BOTH, expand = True)
MyImage1 = PhotoImage(file='Study With4.png')
CanvasImage = page.create_image(0, 0, image = MyImage1, anchor = NW)
label = Frame(root)
label.pack(fill = BOTH, expand = True)
entry = Text(label, height = 29, width = 46, wrap = NONE, bg = '#F8F8F8')
entry.pack(side = LEFT, fill = BOTH, expand = True)
scroll = Scrollbar(label, orient = VERTICAL)
scroll.pack(side=RIGHT, fill=Y)
scroll.config(command = entry.yview)
entry.config(yscrollcommand = scroll.set)
page.pack()
page.create_window(25, 25, window = label, anchor = NW)
mainloop()

Borderwidth attribute in Tkinter not working

I am trying to use borderwidth attribute to highlight only the "New Game" part of the png image, however, it isn't working, how do I solve this error?
from tkinter import *
from PIL import ImageTk, Image
root = Tk()
root.iconbitmap('unnamed.ico')
root.title('2048')
bg = ImageTk.PhotoImage(Image.open("welcome.png"))
new_game_btn = ImageTk.PhotoImage(Image.open("image_40.png"))
my_canvas = Canvas(root, width=780, height=550)
my_canvas.pack()
my_canvas.create_image(0, 0, image=bg, anchor=NW)
button1 = Button(root, image=new_game_btn, borderwidth=00, relief=FLAT)
button1_window = my_canvas.create_window(100, 100, anchor=NW, window=button1)
root.mainloop()
Your only option seems to be to draw the image to the canvas instead of creating a button (because widgets in Tkinter do not support transparency).
The drawback is, that you will have to check the mouse coordinates on the Canvas in order to see if your "Button" has been clicked.
The code would look like this:
from PIL import ImageTk, Image
root = Tk()
root.iconbitmap('unnamed.ico')
root.title('2048')
bg = ImageTk.PhotoImage(Image.open("welcome.png"))
new_game_btn = ImageTk.PhotoImage(Image.open("image_40.png"))
my_canvas = Canvas(root, width=780, height=550)
my_canvas.pack()
my_canvas.create_image(0, 0, image=bg, anchor=NW)
my_canvas.create_image(100, 100, image=new_game_btn, anchor=NW)
root.mainloop()
This results in that (don't mind the typo...):
If you want to check if that part of the canvas was clicked, I would just check for the bounding box like this:
from tkinter import *
from PIL import ImageTk, Image
x_pos = 100
y_pos = 100
width = 100
height = 100
def callback(event):
print("Canvas clicked at", event.x, event.y)
if (event.x > x_pos and event.x < x_pos + width):
if(event.y > y_pos and event.y < y_pos + height):
print("The button was clicked (approximately).")
root = Tk()
root.iconbitmap('unnamed.ico')
root.title('2048')
bg = ImageTk.PhotoImage(Image.open("welcome.png"))
new_game_btn = ImageTk.PhotoImage(Image.open("image_40.png"))
my_canvas = Canvas(root, width=780, height=550)
my_canvas.pack()
my_canvas.create_image(0, 0, image=bg, anchor=NW)
my_canvas.create_image(100, 100, image=new_game_btn, anchor=NW)
my_canvas.bind("<Button-1>", callback)
root.mainloop()

How to equally expand image buttons in Tkinter with grid weight approach?

I'm trying to use tkinter to add squared buttons.
I know that default button size is with text (not pixel), thus I apply following tips to try to create square buttons:
Fix-ranged frame with grid_propagate(False)
grid columnconfigure(x,weight=1)
expand buttons by sticky=W+E+S+N .
The following case (button without image) is fine. All widths of three buttons are equally expanded to 100. Therefore all buttons are 100x100 square.
from tkinter import *
mainwin=Tk()
f = Frame(mainwin,width=300, height=100, bg = "black")
f.pack()
f.grid_propagate(False)
Bt1 = Button(f, bg = "#888888")
Bt1.grid(row=0,column=0,sticky=W+E+S+N)
Bt2 = Button(f, bg = "#AAAAAA")
Bt2.grid(row=0,column=1,sticky=W+E+S+N)
Bt3 = Button(f, bg = "#CCCCCC")
Bt3.grid(row=0,column=2,sticky=W+E+S+N)
f.rowconfigure(0,weight=1)
f.columnconfigure(0,weight=1)
f.columnconfigure(1,weight=1)
f.columnconfigure(2,weight=1)
mainwin.mainloop()
But when I set image (50 pixel) on two buttons, all widths of three buttons are NOT equally expanded. Therefore all buttons are not square.
from tkinter import *
mainwin=Tk()
f = Frame(mainwin,width=300, height=100, bg = "black")
f.pack()
f.grid_propagate(False)
test_image = PhotoImage(file="test_50x50.png")
Bt1 = Button(f, bg = "#888888", compound='c')
Bt1["image"] = test_image
Bt1.grid(row=0,column=0,sticky=W+E+S+N)
Bt2 = Button(f, bg = "#AAAAAA", compound='c')
Bt2["image"] = test_image
Bt2.grid(row=0,column=1,sticky=W+E+S+N)
Bt3 = Button(f, bg = "#CCCCCC", compound='c')
Bt3.grid(row=0,column=2,sticky=W+E+S+N)
f.rowconfigure(0,weight=1)
f.columnconfigure(0,weight=1)
f.columnconfigure(1,weight=1)
f.columnconfigure(2,weight=1)
mainwin.mainloop()
I GUESS that the "initial width" of all buttons will be calculated by (300-50*2)/3,
then the "final width" of buttons with image = initial width + its image width
In the above case final width = 115, 115, 70. For that 115-50(image size) = 65 is close to 70, the difference may be related to boundary or padding...
How could I equally expand image buttons to square-shaped with applying grid weight approach ?
Check This Out. I used a square of size: 50 by 50 pixels.
from tkinter import *
from PIL import ImageTk
mainwin=Tk()
f = Frame(mainwin,width=150, height=50, bg = "black")
f.pack()
f.grid_propagate(False)
image1=ImageTk.PhotoImage(file="D:/test/square.png")
Bt1 = Button(f, bg = "#888888",image=image1)
Bt1.grid(row=0,column=0,sticky=N+W+S+E)
Bt2 = Button(f,image=image1, bg = "#AAAAAA")
Bt2.grid(row=0,column=1,sticky=N+W+S+E)
Bt3 = Button(f,image=image1, bg = "#CCCCCC")
Bt3.grid(row=0,column=2,sticky=N+W+S+E)
f.rowconfigure(0,weight=1)
f.columnconfigure(0,weight=1)
f.columnconfigure(1,weight=1)
f.columnconfigure(2,weight=1)
mainwin.mainloop()

How to to resize canvas objects to window size in tkinter without using object oriented programming?

This is my code so far and I want to resize all of these widgets including the image to window size.
from tkinter import *
win = Tk()
win.title("xxx")
win.geometry("600x600")
win.resizable()
w = 700
h = 700
x = 600 // 2
y = 600 // 2
canvas = Canvas(win, width=w, height=h, bg="grey")
canvas.grid(row=0, column=0, padx=50, pady=50)
img = PhotoImage(file="c.png")
canvas.create_rectangle(0, 0, 75, 500, fill="green")
canvas.create_rectangle(425, 0, 500, 500, fill="green")
canvas.create_rectangle(75, 0, 80, 500, fill="brown")
image = canvas.create_image(x, 440, image=img)
win.mainloop()
You can resize all the items in the canvas using the Canvas.coords(tagorId, x0, y0...). This can be used for any item in the canvas other than the image. For image use Image.resize((x, y), resample).
Bind the <Configure> event to an event handler. So whenever the canvas is resized the event handler is called.
Here is a demo.(Note the other items on the canvas might be hidden by the image). The below code will automatically resize items to the canvas.
from tkinter import *
from PIL import ImageTk, Image
def resize_widgets(event):
global resized
for items in canvas.find_all():
if items != image:
canvas.coords(items, 0, 0, event.width, event.height)
resized = ImageTk.PhotoImage(im.resize((event.width, event.height), resample = Image.NEAREST))
canvas.itemconfig(image, image=resized)
canvas.moveto(image, 0, 0)
win = Tk()
win.title("Dodge Car Challenger")
win.geometry("600x600")
win.resizable()
w = 700
h = 700
x = 600 // 2
y = 600 // 2
resized = None
canvas = Canvas(win, width=w, height=h, bg="grey")
#canvas.grid(row=0, column=0, padx=50, pady=50)
canvas.pack(expand=True, fill='both')
canvas.bind('<Configure>', resize_widgets)
im = Image.open(r"your imagepath")
img = ImageTk.PhotoImage(im)
canvas.create_rectangle(0, 0, 75, 500, fill="green")
item = canvas.create_rectangle(425, 0, 500, 500, fill="green")
canvas.create_rectangle(75, 0, 80, 500, fill="brown")
image = canvas.create_image(x, 440, image=img)
win.mainloop()

Can you rescale a PhotoImage in Python Tkinter?

In my program, I have two buttons. button1 calls a function (bt1) which displays an image in the window and then deletes both buttons. button2 calls a function(bt2) I would like this button to display the same image as button1 but by half the scale factor. I am thinking something like this:
scale_half_img = PhotoImage(file = 'Image.png', scale = 0.5)
Of course, this doesn't work but this is the sort of thing I am looking for.
Full code:
from tkinter import *
window = Tk()
def bt1():
img = PhotoImage(file = 'Image.png')
imglbl = Label(window, image = img, anchor = 'nw')
imglbl.place(x = 0, y = 0, width = 865, height = 800)
button1.destroy()
button2.destroy()
def bt2():
# display scaled down image
button1.destroy()
button2.destroy()
button1 = Button(window, text = 'Display Image', command = bt1)
button1.place(x = 10, y = 10, width = 200, height = 30)
button2 = Button (window, text = 'Display Rescaled Image', command = bt2)
button2.place(x = 10, y = 50, width = 200, height = 30)
window.mainloop()
Use PIL.Image to resize an image in tkinter. You can do it as follows:
from PIL import Image, ImageTk
img = Image.open('<Path to Image>')
img = img.resize((img.size[0]/2, img.size[1]/2), Image.ANTIALIAS)
resized_image = ImageTk.Photoimage(img) # use this

Categories