Tkinter button doesn't work when I add an image on this button - python-3.x

I'm creating a button with tkinter but I want to had an image on this button. When I make it, the button doesn't work. Nonetheless, when I remove the image of my button, it works..
# Creating a photoimage object to use image
photo = PhotoImage(file = r"C:/Users/toto/Documents/toto/img/Flechedroiteverte.png")
# Resizing image to fit on button
photoimage = photo.subsample(1, 1)
PageSuivante=Button(main_win, text = 'Click Me !', image = photoimage)
PageSuivante.grid(pady = 10)

You have to keep a reference in a label, I have the same problem. You can do something like:
add = PhotoImage(file=r"C:/Users/toto/Documents/toto/img/Flechedroiteverte.png")
label = Label(image=add)
label.image = add # keep a reference!
PageSuivante=Button(main_win, text = 'Click Me !', image = add)

def ShowFramePrepaChantier(main_win,frame):
delete_frame(main_win)
frame.tkraise()
frame.place(x=0, y=0)
bouton_DownloadDPA = Button(frame, text='Valider mes DPA sélectionnées',padx = 200)
bouton_DownloadDPA.grid(row=1, column=0, sticky=SE)
bouton_DownloadDPA.bind('<Button-1>', select)
## Creating a photoimage object to use image
photo = PhotoImage(file = r"C:/Users/toto/Documents/toto/img/Flechedroiteverte.png")
# Resizing image to fit on button
photoimage = photo.subsample(10, 10)
# here, image option is used to
# set image on button
# compound option is used to align
# image on LEFT side of button
bouton = Button(frame, text = 'Click Me !', image = photoimage,
compound = LEFT)
bouton.grid(pady = 100)
if __name__ == "__main__":
main_win = Tk()
main_win.configure(bg='lavender')
main_win.title("Test")
main_win.geometry("680x400")
second_frame = Frame(main_win)
bouton_PrepaChantier = Button(main_win, text='Click to change frame', command=lambda:ShowFramePrepaChantier(main_win,second_frame), height=3, width=20)
bouton_PrepaChantier.grid()
main_win.mainloop()

Related

Background Image Adjustment on Top Level Window with Tkinter

I have a basic GUI that begins with a main menu of sorts. I have successfully set a background image to that menu and it also scales when I change the dimension of the GUI window.
However when I try to define some top-level windows that are opened by the sub-menu items the background image does not appear (not to mention scale).
Not sure what I'm doing wrong but I'm attaching the code I wrote along with the images of the basic GUI.
from tkinter import *
from tkinter import ttk, font, messagebox
from PIL import ImageTk, Image
import os
root = Tk()
root.title("Decoder of ultrasound images to detect colon tumors")
# Adding window icon
root.iconbitmap('afekaImage.ico')
rootWidth, rootHeight = 600, 600
screenWidth = root.winfo_screenwidth()
screenHeight = root.winfo_screenheight()
topLeftPosition = (screenWidth / 2 - rootWidth / 2, screenHeight / 2 - rootHeight / 2)
# Configure window size
root.geometry(f'{rootWidth}x{rootHeight}+{int(topLeftPosition[0])}+{int(topLeftPosition[1])}')
'''
# Create username & password entry
def entryDialog():
userName = entry1.get()
password = entry2.get()
if ((userName == 'Itzhak.Mamistvalov' and password == '311396832') or
(userName == 'AssafHasky' and password == '308333533')):
messagebox.showinfo('info', 'Correct Login')
else:
messagebox.showinfo('info', 'Invalid Login') '''
# open doc file
def openDocFile():
os.startfile("mid_sub.docx")
# adjusting background image to fit window
def adjustBackgroundImage(event):
# avoid garbage collection option 1
# global resizedBackgroundImage, newBackgroundImage
# ----------
width = event.width
height = event.height
resizedBackgroundImage = copyImage.resize((width, height))
newBackgroundImage = ImageTk.PhotoImage(resizedBackgroundImage)
label.config(image=newBackgroundImage)
# avoid garbage collection option 2
label.image = newBackgroundImage
# ----------
def createUserManualWindow(button_userManual):
global image1
userManualWindow = Toplevel(root)
def activateButtonUserManual():
button_userManual.configure(state="normal")
userManualWindow.destroy()
button_userManual.configure(state="disabled")
button_exit_userManualWindow = Button(userManualWindow, text="Exit", font=fontStyle,
command=lambda: [userManualWindow.destroy(), activateButtonUserManual()])
button_exit_userManualWindow.place(relx=0.4, rely=0.8, relwidth=0.2, relheight=0.1)
# will occurs only when esc pressed
userManualWindow.protocol("WM_DELETE_WINDOW", activateButtonUserManual)
# ----------
userManualWindow.geometry(f'{rootWidth}x{rootHeight}+{int(topLeftPosition[0])}+{int(topLeftPosition[1])}')
userManualWindow.iconbitmap('afekaImage.ico')
image1 = ImageTk.PhotoImage(Image.open('background.jpg'))
label1 = ttk.Label(userManualWindow, image=image1).pack()
label1.bind('<Configure>', adjustBackgroundImage)
label1.pack(fill=BOTH, expand=YES)
def createOverviewWindow(button_userManual):
overviewWindow = Toplevel(root)
def activateButtonOverview():
button_userManual.configure(state="normal")
overviewWindow.destroy()
button_userManual.configure(state="disabled")
button_exit_OverviewWindow = Button(overviewWindow, text="Exit", font=fontStyle,
command=lambda: [overviewWindow.destroy(), activateButtonOverview()])
button_exit_OverviewWindow.place(relx=0.4, rely=0.8, relwidth=0.2, relheight=0.1)
# will occurs only when esc pressed
overviewWindow.protocol("WM_DELETE_WINDOW", activateButtonOverview)
# ----------
overviewWindow.geometry(f'{rootWidth}x{rootHeight}+{int(topLeftPosition[0])}+{int(topLeftPosition[1])}')
overviewWindow.iconbitmap('afekaImage.ico')
# Define background image
image = Image.open('background.jpg')
copyImage = image.copy()
backgroundImage = ImageTk.PhotoImage(image)
label = ttk.Label(root, image=backgroundImage)
label.bind('<Configure>', adjustBackgroundImage)
label.pack(fill=BOTH, expand=YES)
# Configure font
fontStyle = font.Font(family="Segoe Script", size=10, weight=font.BOLD)
# Create buttons
button_userManual = Button(root, text="USER MANUAL", command=lambda: createUserManualWindow(button_userManual), font=fontStyle)
button_userManual.place(relx=0.4, rely=0.2, relwidth=0.2, relheight=0.1)
button_overview = Button(root, text="OVERVIEW", command=lambda: createOverviewWindow(button_overview), font=fontStyle)
button_overview.place(relx=0.4, rely=0.4, relwidth=0.2, relheight=0.1)
button_openDocFile = Button(root, text="DOC FILE", font=fontStyle, command=openDocFile)
button_openDocFile.place(relx=0.4, rely=0.6, relwidth=0.2, relheight=0.1)
button_quit = Button(root, text="Exit", font=fontStyle, command=root.destroy)
button_quit.place(relx=0.4, rely=0.8, relwidth=0.2, relheight=0.1)
root.mainloop()
label1 = ttk.Label(userManualWindow, image=image1).pack() should be changed to:
label1 = ttk.Label(userManualWindow, image=image1)
label1.pack()
You should call label1.pack() before placing the "Exit" button, otherwise it will overlap/hide the "Exit" button. Or call label1.lower() after label1.pack().
label is used inside adjustBackgroundImage(), so even though you bind <configure> on label1 to adjustBackgroundImage(), it would not resize image shown by label1. Use event.widget instead of label inside adjustBackgroundImage():
def adjustBackgroundImage(event):
label = event.widget
# avoid garbage collection option 1
# global resizedBackgroundImage, newBackgroundImage
# ----------
width = event.width
height = event.height
resizedBackgroundImage = copyImage.resize((width, height))
newBackgroundImage = ImageTk.PhotoImage(resizedBackgroundImage)
label.config(image=newBackgroundImage)
# avoid garbage collection option 2
label.image = newBackgroundImage
# ----------

how to add image in tkinter?

I can't add image (gif image) to tkinter window.
from tkinter import *
from tkinter import filedialog
from PIL import ImageTk, Image
root = Tk()
def open_image():
qr_select = filedialog.askopenfilename(title = "open")
im = PhotoImage(file=qr_select)
w1 = Label(window, image = im)
w1.image = im
w1.config(image=im)
w1.pack(side="right")
def window_function():
global window
window=Tk()
window.geometry("800x550+650+250")
window.title("QR_Scanner")
btn = Button(window,text = "open a gif picture",command = open_image)
btn.pack()
root.iconify()
window.mainloop()
btn = Button(root,text = "open window",command = window_function)
btn.pack()
root.mainloop()
my error is (_tkinter.TclError: image "pyimage1" doesn't exist)
The reason you can't see your gif in the window is that you haven't made a reference to the image so it is collected in Tkinters garbage collector. Read More About This Here. To Add a reference to the image you can do this:
w1.image = im
And add it in your code here:
def open_image():
qr_select = filedialog.askopenfilename(title = "open")
im = PhotoImage(file=qr_select)
w1 = Label(root, image = im)
w1.image = im #Keep A Reference To The Image
w1.config(image=im)
w1.pack(side="right")
The reason you are getting pyimage1 doesn't exist is because you have more than one instance the Tk and there is only meant to be 1. You have to make your window a Toplevel() by replacing: window=Tk() with window=TopLevel()

Skip files on button click [tkinter + Python 3.5]

Suppose I have 'n' image files in a directory filedir which I want to view via tkinter console. Now, I want to skip a few files whenever necessary, using a button click event which invokes a function nextFile().
E.g.
import os
def nextFile():
global img
img_2 = process(img)
return img_2
window = tk.Tk()
window.title("File Viewer")
files = os.listdir(filedir)
button1 = tk.Button(window, text="Browse Files...", fg="black", command=askopenfilename)
button2 = tk.Button(window, text="SELECT", width=50, command=nextFile)
canvas = tk.Canvas(window, width=width, height=height)
button1.pack(side=tk.LEFT)
button2.pack(side=tk.BOTTOM)
canvas.pack()
for f in files:
img = cv2.cvtColor(cv2.imread(filedir + '/' + f), cv2.COLOR_BGR2RGB)
photo = ImageTk.PhotoImage(image=Image.fromarray((img))
canvas.create_image(0, 0, image=photo, anchor=tk.CENTER)
window.mainloop()
Any help is appreciated. Thanks!
Here is a simple example using PIL to load the inital image and then use a button and function to load each next image.
import tkinter as tk
from PIL import ImageTk, Image
import os
path = 'C:/your/file/path/here'
def nextFile():
# the global is needed to keep track of current index and also keep
# a reference of the image being displayed so its is not garbage collected.
global current_ndex, image
current_ndex += 1
if current_ndex < len(files):
img = Image.open('{}/{}'.format(path, files[current_ndex]))
image = ImageTk.PhotoImage(img)
# clear the canvas before adding the new image.
canvas.delete("all")
canvas.create_image(0, 0, image=image, anchor=tk.CENTER)
my_window = tk.Tk()
my_window.title("File Viewer")
files = os.listdir(path)
current_ndex = 0
button2 = tk.Button(my_window, text="Next", width=50, command=nextFile)
canvas = tk.Canvas(my_window, width=100, height=100)
button2.pack(side=tk.BOTTOM)
canvas.pack()
first_image = files[0]
img = Image.open('{}/{}'.format(path, first_image))
image = ImageTk.PhotoImage(img)
canvas.create_image(0, 0, image=image, anchor=tk.CENTER)
my_window.mainloop()

Update canvas image on button click event

I'm trying to modify the displayed image on a canvas when a button is clicked on.
I have an object "Window" which will contain my window layers. this object contain a canvas named "draw_frame" and a button named "source_button". I add the command "self.load_static_source" to my button but when i click on my button nothing happen.
(Not exactely nothing because i tried to add default background in the init scope and when i click on my button after that the image on the canvas just diseappeared and the new selected image wasn't draw).
Here is my code:
from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk
DARK_THEME = "grey"
LIGHT_THEME = "white"
THEME = LIGHT_THEME
class Window():
# object constructor
def __init__(self, root, theme):
# Sections #
self.toolbar_frame = LabelFrame(root, bg=theme, height="40")
self.toolbar_frame.pack(side=TOP, fill=X)
# Canvas #
self.draw_frame = Canvas(root)
self.draw_frame.pack(side=RIGHT, fill=BOTH, expand=True)
self.frame = self.draw_frame.create_image(0, 0, anchor=NW)
# Buttons #
self.source_button = Button(self.toolbar_frame, text="Source", bg=theme, command= lambda: self.load_static_source("./Sources/"))
self.source_button.pack(side=LEFT)
# Load image with tk compatibility
def load_image(self, path_):
print(path_) ### DEBUG ###
image = Image.open(path_)
return ImageTk.PhotoImage(image)
# Change canvas source with static one
def load_static_source(self, dir_):
path_ = filedialog.askopenfilename(initialdir = dir_, title = "Select file", filetypes = (("jpeg files","*.jpg"),("all files","*.*")))
self.draw_frame.itemconfig(self.frame, image=self.load_image(path_))
root = Tk()
Window(root, THEME)
root.mainloop()
I found an other post talking about that and i can't find difference between what i did and the given solution and that's why i don't understand why that code isn't working.
Here are the exemple i found and the related post:
from Tkinter import *
#----------------------------------------------------------------------
class MainWindow():
#----------------
def __init__(self, main):
# canvas for image
self.canvas = Canvas(main, width=60, height=60)
self.canvas.grid(row=0, column=0)
# images
self.my_images = []
self.my_images.append(PhotoImage(file = "ball1.gif"))
self.my_images.append(PhotoImage(file = "ball2.gif"))
self.my_images.append(PhotoImage(file = "ball3.gif"))
self.my_image_number = 0
# set first image on canvas
self.image_on_canvas = self.canvas.create_image(0, 0, anchor = NW, image = self.my_images[self.my_image_number])
# button to change image
self.button = Button(main, text="Change", command=self.onButton)
self.button.grid(row=1, column=0)
#----------------
def onButton(self):
# next image
self.my_image_number += 1
# return to first image
if self.my_image_number == len(self.my_images):
self.my_image_number = 0
# change image
self.canvas.itemconfig(self.image_on_canvas, image = self.my_images[self.my_image_number])
#----------------------------------------------------------------------
root = Tk()
MainWindow(root)
root.mainloop()
Related post : stackoverflow topic
You need to keep a reference to the image. Here's a link to the effbot page describing it: https://effbot.org/tkinterbook/photoimage.htm
You must keep a reference to the image object in your Python program, either by storing it in a global variable, or by attaching it to another object.
The solution Xeyes wrote is right, and this page explains.
So i found the solution. A bit weird but it works. I have to save the image in a class attribute before i give it to the canvas itemconfig method.
It now looks like :
self.placeholder = self.load_image(path_)
self.draw_frame.itemconfig(self.frame, image=self.placeholder)
Instead of just :
self.draw_frame.itemconfig(self.frame, image=self.load_image(path_))

Trying to hide a label in tkinter after pressed a button

I'm trying to hide some labels in my code of tkinter.
I'm loading images and then I apply some pre-processing techinque by the moment.
The case is, i have three labels which were added to the widget called "miframe" and all those are in the same coordinates:
labelmaduro = Label(miframe, image=ruta_maduro).place(x=25, y=60)
labelpinton = Label(miframe, image=ruta_pinton).place(x=25, y=60)
labelverde = Label(miframe, image=ruta_verde).place(x=25, y=60)
All the labels are added to frame one over another, I'm finding a way of hide all those labels after push the button "Select Image" and when I pushed the button calle "Predict" show i.g the "labelmature".
I should hide all those labels when the program has already started, but by the moment i can't do that,
I tryed used label1.lower() place_forget()to hide those labels and to show it, I tryed mylabel.pack()
from tkinter import *
import cv2
from PIL import Image
from PIL import ImageTk
from tkinter import filedialog as fd
import numpy as np
def select_image():
# grab a reference to the image panels
global panelA, panelB
# open a file chooser dialog and allow the user to select an input
# image
#ocultar clase predecida anteriormente:
path = fd.askopenfilename()
# ensure a file path was selected
if len(path) > 0:
# load the image from disk, convert it to grayscale, and detect
# edges in it
image = cv2.imread(path)
median = cv2.medianBlur(image, 9)
#Resize
#BGT TO RGB
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
median = cv2.cvtColor(median, cv2.COLOR_BGR2RGB)
dim = (340, 257)
original = cv2.resize(image, dim, interpolation = cv2.INTER_AREA)
median = cv2.resize(median, dim, interpolation = cv2.INTER_AREA)
# Convertir imagenes al formato PIL
original = Image.fromarray(original)
median = Image.fromarray(median)
#Pass to ImageTk format
original = ImageTk.PhotoImage(original)
median = ImageTk.PhotoImage(median)
#if the panels are none
if panelA is None or panelB is None:
#El primer panel guarda la primera imagen
panelA = Label(image=original)
panelA.image = original
panelA
panelA.pack(side="left", padx=10, pady=10)
#the second panel show the pre-processed image
panelB = Label(image=median)
panelB.image = median
panelB.pack(side="right", padx=10, pady=10)
hideLabels()
#in other cases update the panels
else:
# update the pannels
panelA.configure(image=original)
panelB.configure(image=median)
panelA.image = original
panelB.image = median
hideLabels()
def hideGreen():
labelverde.place_forget()
def hideLabels():
hideGreen()
def showMature():
labelmaduro.pack() #show label after push Predict Button
#Initialize the main window
root = Tk()
root.configure(background='black')
root.title("Opencv test")
panelA = None
panelB = None
#Frame which contains the labels
miframe = Frame(bg="#0F2D80", width="200", height="200")
ruta_maduro = PhotoImage(file="maduro.png")
ruta_pinton = PhotoImage(file="pinton.png")
ruta_verde = PhotoImage(file="verde.png")
#Create labels to show and hidde according to the prediction
labelmaduro = Label(miframe, image=ruta_maduro).place(x=25, y=60)
labelpinton = Label(miframe, image=ruta_pinton).place(x=25, y=60)
labelverde = Label(miframe, image=ruta_verde).place(x=25, y=60)
#add frame to root
miframe.pack(side="right", anchor="n", padx=10)
#User buttons
btn2 = Button(root, text="Predict Button", command=showMature)
btn2.pack(side="bottom", fill="both", expand="yes", padx="10", pady="10")
btn = Button(root, text="Select Image", command=select_image)
btn.pack(side="bottom", fill="both", expand="yes", padx="10", pady="10")
root.resizable(0,0)
# kick off the GUI
root.mainloop()
I want to hide all those labels and show only one of them after pressing the "predict" button, but when the program has already started all those labels should be hided, therefore i should only show one label according the predicted class.
You have None values in all of those 3 Labels, that is because you're assigning Label's method place(..) return value to the objects of those Labels, as place returns None (same for pack or grid).
Always do,
labelmaduro = Label(miframe, image=ruta_maduro)
labelmaduro.place(x=25, y=60)
Or if you want no object for a Label and just want to assign it without modifying it further in your code then you can use it like this.
Label(miframe, image=ruta_maduro).place(x=25, y=60)
Now for hiding labels.
You don't need three labels to show / hide to achieve that kind of functionality. It can be done by modifying the image of the existing Label so in that case you just need one Label and configure it's image resource to different one depending on your need like so...
img_label.config(image=ruta_pinton)
Here is an example of changing images of a single Label from different Buttons.
from tkinter import *
root = Tk()
ruta_maduro = PhotoImage(file="maduro.png")
ruta_pinton = PhotoImage(file="pinton.png")
ruta_verde = PhotoImage(file="verde.png")
img_label = Label(root)
img_label.pack()
Button(root, text='maduro', command=
lambda: img_label.config(image=ruta_maduro)).pack()
Button(root, text='maduro', command=
lambda: img_label.config(image=ruta_pinton)).pack()
Button(root, text='maduro', command=
lambda: img_label.config(image=ruta_verde)).pack()
mainloop()

Resources