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

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()

Related

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

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

Displaying frames in TKinter without classes

I'm currently writing a library system and, in order to better understand how to change between frames, have so far have written code for a screen the user is met with when they first use the program as shown below:
import tkinter as tk
import json
window = tk.Tk() # creates a window
width = 474 # sets the width and height of the screen
height = 266
screen_width = window.winfo_screenwidth() # finds the width of the user's screen
screen_height = window.winfo_screenheight()
center_x = int(screen_width / 2 - width / 2)
center_y = int(screen_height / 2 - height / 2)
window.geometry(f'{width}x{height}+{center_x}+{center_y}') # sets the width, height, and positioning of the window
window.title("Library System") # sets title of window
window.resizable(False, False) # Prevents the window being resized by both the x and y coordinates
welcome = tk.Frame(width=200, height=200, background="light cyan")
ChangeInfo = tk.Frame(window, width=400, height=200)
ChangeInfo.pack(fill='both', expand=True, padx=0, pady=0)
def WelcomeScreen():
greeting = tk.Label(welcome, text="Welcome", font=("comic sans", 15), bg ='light cyan') # creates a lable with text
greeting.pack()
explaination = tk.Label(welcome, text="This is your first time using this program so please click the button below to "
"enter in \n the username "
"and password you will be using to log into the system in the future"
"", font=("comic_sans", 9), bg="light cyan")
explaination.place(x = (width)/2, y= 50, anchor='center')
login_button = tk.Button(welcome, text="Set username and password", height=3, width=22,
font=("comic_sans", 10), bg = "turquoise")
login_button.place(x= width / 2, y= height / 2, anchor='center')
window.mainloop()
WelcomeScreen()
The only thing that is displayed at the moment is the window and its title. How do I display the frame instead of only the window?
If you want to show the welcome frame initially, you need to call welcome.pack(...) instead of ChangeInfo.pack(...).

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()

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

Cannot make that scroll bar shows frame untill the bottom

I am trying to create a pop up help window for a tool. I managed to add the scrollbar to a frame that contains canvas and label widget. However that Scrollbar does not shows the img_canvas_3 that I added.
Here is my code:
from tkinter import *
import tkinter.filedialog
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import askdirectory
import PIL
from PIL import Image, ImageTk
help_window = tkinter.Tk()
help_window.title("Help")
help_window.geometry("400x800")
#frame.grid(row=0,column=0)
canvas=Canvas(help_window,bg='red',width=300,height=800,scrollregion=(0,0,500,500))
scroll_y = Scrollbar(help_window, orient="vertical", command = canvas.yview)
frame=Frame(canvas,width=300,height=800, bg="green")
description_label = Label(frame, text = "\n\tMy Tool\n",anchor = "w").pack(side = TOP, fill = "both")
introduction = "This tool provides a basic workflow"
introduction_text = Label(frame, text = introduction, anchor = "w", font = "Verdana 10", bg="yellow").pack(fill = "both")
label_1 = Label(frame, text = "Input Data 1", anchor = "w", font = "Verdana 10", justify=CENTER).pack(fill = "both")
img_canvas_1 = Canvas(frame, bg = "black", height = 300, width = 300)
img_canvas_1.pack(side = TOP)
label_2 = Label(frame, text = "Input Data 2", anchor = "w", font = "Verdana 10", justify = CENTER).pack(fill = "both")
img_canvas_2 = Canvas(frame, bg = "black", height = 300, width = 300)
img_canvas_2.pack(side = TOP)
label_3 = Label(frame, text = "Input Data 3", anchor = "w", font = "Verdana 10", justify = CENTER).pack(fill = "both")
img_canvas_3 = Canvas(frame, bg = "black", height = 300, width = 300)
img_canvas_3.pack(side = TOP)
canvas.create_window(0, 0, anchor = 'nw', window = frame)
canvas.update_idletasks
canvas.configure(scrollregion=canvas.bbox('all'),
yscrollcommand = scroll_y.set)
canvas.pack(fill = 'both', expand = TRUE, side = 'left')
scroll_y.pack(fill = 'y', side = 'right')
help_window.mainloop()
I expected to have the scroll bar working, basically showing all the widgets and elements in the frame as I am adding more and more. That is only true for the untill img_canvas_2
Does anyone have an idea why this is not the case with my code? I tried by playing around with the scrollregion parameter in the canvas variable, but it did not work.
Thanks in advance.

Categories