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()
Related
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
# ----------
I am using Tkinter, I want to clear the canvas using a button(close_button) but the camera is always on and the button not doing anything I want the button to close the camera feed and reset the canvas so that the canvas becomes as it was before I opened the cam
from tkinter import*
import tkinter as tk
from PIL import Image, ImageTk
import cv2
# new window function which will be called when button pressed
class OpenCam():
def __init__(self, window, cap):
self.window = window
self.cap = cap
self.width = self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
self.interval = 20 # Interval in ms to get the latest frame
# Create canvas for image
self.canvas = tk.Canvas(self.window, width=self.width, height=self.height)
self.canvas.place(x=100,y=100)
# close Button need to close cam and reset canvas
close_button = tk.Button(root, text="close", bg='black', fg='white', command=self.canvas.delete() )
close_button.place(x=610,y=0)
# Update image on canvas
self.update_image()
def update_image(self):
# Get the latest frame and convert image format
self.image = cv2.cvtColor(self.cap.read()[1], cv2.COLOR_BGR2RGB) # to RGB
self.image = Image.fromarray(self.image) # to PIL format
self.image = ImageTk.PhotoImage(self.image) # to ImageTk format
# Update image
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image)
# Repeat every 'interval' ms
self.window.after(self.interval, self.update_image)
def new_window():
OpenCam(root, cv2.VideoCapture(0))
#create original window
root = tk.Tk()
root.title("ADD CAM: ")
canvas = tk.Canvas(root, height=1000, width=1000)
canvas.pack()
#create button that will be placed
button = tk.Button(root, text="ADD CAM", bg='black', fg='white', command=new_window )
button.place(x=0,y=0)
root.mainloop()
As in question is it possible to upload a photo and make it relative?
I am trying to upload an image to my GUI, but it is not relative, so when you maximalize window, then unfortunatelly there is a problem with its size.
I want to change the image size dynamically when the window is resizing
Some example code:
import tkinter as tk
from PIL import ImageTk, Image
HEIGHT, WIDTH = 640, 700
root = tk.Tk()
canvas0 = tk.Canvas(height=HEIGHT, width=WIDTH)
canvas0.pack()
canvas = tk.Canvas(bg='black')
canvas.place(relx=0, rely=0, relheight=1, relwidth=1)
frame = tk.Frame(canvas, bg='#009900')
frame.place(relx=0.12, y=2, rely=0, relwidth=0.75, relheight=1)
column_1_img = Image.open('column.png')
column_1_img = ImageTk.PhotoImage(column_1_img)
column_label_1 = tk.Label(canvas, image=column_1_img)
column_label_1.image = column_1_img
column_label_1.place(relheight=1, relwidth=0.2)
root.mainloop()
This code produces this output:
Not fullscreen
Fullscreen
I want an image to automatically adjust to the label size, so do you have some ideas how?
Bind the <Configure> to an event handler and use the PIL's resize method to resize the image.
Here is an example:
import tkinter as tk
from PIL import ImageTk, Image
def resize_image(event):
column_label_1.resized = ImageTk.PhotoImage(column_1_img.resize((event.width, event.height), resample = Image.NEAREST))
column_label_1['image'] = column_label_1.resized
HEIGHT, WIDTH = 640, 700
root = tk.Tk()
canvas0 = tk.Canvas(height=HEIGHT, width=WIDTH)
canvas0.pack()
canvas = tk.Canvas(bg='black')
canvas.place(relx=0, rely=0, relheight=1, relwidth=1)
frame = tk.Frame(canvas, bg='#009900')
frame.place(relx=0.12, y=2, rely=0, relwidth=0.75, relheight=1)
column_1_img = Image.open(r'img_path')
column_img = ImageTk.PhotoImage(column_1_img)
column_label_1 = tk.Label(canvas, image=column_img)
column_label_1.image = column_1_img
column_label_1.place(relheight=1, relwidth=0.2)
column_label_1.bind('<Configure>', resize_image)
root.mainloop()
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_))
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()