I have a working code where tkinter application fetches a GIF file and displays it on clicking a button
It is working fine for a single GIF image.
What I want is to have an additional button for Next image and when I click on it, it should display next image. How can I create list of images?
from tkinter import *
from PIL import Image, ImageTk
class MyLabel(Label):
def __init__(self, master, filename):
im = Image.open(filename)
seq = []
try:
while 1:
seq.append(im.copy())
im.seek(len(seq)) # skip to next frame
except EOFError:
pass # we're done
try:
self.delay = im.info['duration']
except KeyError:
self.delay = 100
first = seq[0].convert('RGBA')
self.frames = [ImageTk.PhotoImage(first)]
Label.__init__(self, master, image=self.frames[0])
temp = seq[0]
for image in seq[1:]:
temp.paste(image)
frame = temp.convert('RGBA')
self.frames.append(ImageTk.PhotoImage(frame))
self.idx = 0
self.cancel = self.after(self.delay, self.play)
self.button = Button(text="Zoom out",command=self.play)
self.button.place(relx=0.4, rely=0.5, anchor=CENTER)
def play(self):
self.config(image=self.frames[self.idx])
self.idx += 1
if self.idx == len(self.frames):
self.idx = 0
self.cancel = self.after(self.delay, self.play)
root = Tk()
def stop_it():
anim.after_cancel(anim.cancel)
anim = MyLabel(root,'A.gif')
anim.pack()
stop_it()
root.mainloop()
My idea is if I can use below sort of code:
images = ['A.gif','B.gif']
images = iter(images)
img = next(images)
But how I can implement this in my current code?
Probably there are many ways for making a list of images , but I would make it like this :
# images
img1 = ImageTk.PhotoImage(Image.open("a.gif"))
img2 = ImageTk.PhotoImage(Image.open("b.gif"))
img3 = ImageTk.PhotoImage(Image.open("c.gif"))
# a list of images
Image_list = [img1 , img2 , img3 ]
For iterating I would make something like a counter
counter = len(Image_list)
img_panel = Label(root , image = Image_list[counter] )
img_panel.pack()
def next_image():
counter-=1
img_panel = Label(root , image = Image_list[counter] )
img_panel.pack()
next_image = Button(root , text= "next image" , command =next_image)
next_image.pack()
Related
I was trying to make an image slideshow program with Tkinter and Python3. No errors, but not showing the images that are inside my chosen directory. The other libraries that I have use are: PIL, random and glob. Your help will be greatly appreciated.
My system:
Ubuntu 20.04 LTS
Here is the code:
import tkinter as Tk
from PIL import Image, ImageTk
import random
import glob
class gui:
def __init__(self, mainwin):
self.counter = 0
self.mainwin = mainwin
self.mainwin.title("Our Photos")
self.colour()
self.mainwin.configure(bg = "yellow")
self.Frame = Tk.Frame(mainwin)
self.img = Tk.Label(self.Frame)
self.Frame.place(relheight = 0.85, relwidth = 0.9, relx = 0.05, rely = 0.05 )
self.img.pack()
self.pic()
def colour(self):
self.colours =['gray47','gray48']
c = random.choice(self.colours)
self.mainwin.configure(bg = c)
root.after(4000, self.colour)
def pic(self):
for name in glob.glob(r"/home/maheswar/Pictures/*"):
self.pic_list = []
val = name
self.pic_list.append(val)
if self.counter == len(self.pic_list) - 1:
self.counter = 0
else:
self.counter == self.counter + 1
self.file = self.pic_list[self.counter]
self.load = Image.open(self.file)
self.pic_width = self.load.size[0]
self.pic_height = self.load.size[1]
self.real_aspect = self.pic_width/self.pic_height
self.calc_width = int(self.real_aspect * 800)
self.load2 = self.load.resize((self.calc_width, 800))
self.render = ImageTk.PhotoImage(self.load2)
self.img.config(image = self.render)
self.img.image = self.render
root.after(2000, self.pic)
root = Tk.Tk()
myprog = gui(root)
root.geometry("1000x1000")
root.mainloop()
I found two mistaces - which probably you could see if you would use print() to debug code
First: you create list self.pic_list = [] inside loop so you replace previous content and this way you can get only one list. But you don't event need this loop but directly
self.pic_list = glob.glob(r"/home/maheswar/Pictures/*")
Second: you need = instead of == in line self.counter = self.counter + 1 or even simpler
self.counter += 1
Full working code with small changes.
import tkinter as Tk
from PIL import Image, ImageTk
import random
import glob
class GUI: # PEP8: `CamelCaseNames` for classes
def __init__(self, mainwin):
self.mainwin = mainwin
self.mainwin.title("Our Photos")
self.mainwin.configure(bg="yellow") # PEP8: inside `()` use `=` without spaces
self.counter = 0
self.frame = Tk.Frame(mainwin) # PEP8: `lower_case_names` for variables
self.frame.place(relheight=0.85, relwidth=0.9, relx=0.05, rely=0.05)
self.img = Tk.Label(self.frame)
self.img.pack()
self.pic_list = glob.glob("/home/maheswar/Pictures/*") # no need prefix `r`
self.colours = ['gray47', 'gray48'] # PEP8: space after `,`
self.colour()
self.pic()
def colour(self):
selected = random.choice(self.colours)
self.mainwin.configure(bg=selected)
root.after(4000, self.colour)
def pic(self):
filename = self.pic_list[self.counter]
image = Image.open(filename)
real_aspect = image.size[0]/image.size[1]
width = int(real_aspect * 800)
image = image.resize((width, 800))
self.photo = ImageTk.PhotoImage(image)
self.img.config(image=self.photo)
#self.img.image = self.render no need if you use `self.` to keep PhotoImage
self.counter += 1
if self.counter >= len(self.pic_list):
self.counter = 0
root.after(2000, self.pic)
# --- main ---
root = Tk.Tk()
myprog = GUI(root)
root.geometry("1000x1000")
root.mainloop()
PEP 8 -- Style Guide for Python Code
I've found a way to display an animated GIF using Python tkinter and I'm trying to make it work with Python Turtle Graphics.
I can get the animated gif to display with the following code, but there are issues.
1) For some reason having .grid(row=0, column=0) puts the image off-screen.
2) The image has a surrounding border which I don't want to display.
I've tried .place() with various arguments, but none those place the image on the screen.
Any suggestions on how to place the image a a specific position without a border please?
# main file
import turtle
import tkinter_gif
screen = turtle.Screen()
canvas = screen.getcanvas()
gif_window = tkinter_gif.ImageLabel(canvas)
gif_window.grid(row=1, column=0)
gif_window.load("giphy.gif")
turtle.done()
# tkinter_gif.py
import tkinter as tk
from PIL import Image, ImageTk
from itertools import count
class ImageLabel(tk.Label):
"""a label that displays images, and plays them if they are gifs"""
def load(self, im):
if isinstance(im, str):
im = Image.open(im)
self.loc = 0
self.frames = []
try:
for i in count(1):
self.frames.append(ImageTk.PhotoImage(im.copy()))
im.seek(i)
except EOFError:
pass
try:
self.delay = im.info['duration']
except:
self.delay = 100
if len(self.frames) == 1:
self.config(image=self.frames[0])
else:
self.next_frame()
def unload(self):
self.config(image=None)
self.frames = None
def next_frame(self):
if self.frames:
self.loc += 1
self.loc %= len(self.frames)
self.config(image=self.frames[self.loc])
self.after(self.delay, self.next_frame)
I suggest to change ImageLabel from tk.Label to image item of Canvas as below:
class ImageLabel:
def __init__(self, canvas):
self.canvas = canvas
def load(self, im, x=0, y=0):
# create a canvas image item
self.image = self.canvas.create_image(x, y, image=None)
self.canvas.tag_lower(self.image)
if isinstance(im, str):
im = Image.open(im)
self.frames = []
try:
for i in count(1):
self.frames.append(ImageTk.PhotoImage(im.copy()))
im.seek(i)
except EOFError:
pass
try:
self.delay = im.info['duration']
except:
self.delay = 100
num_frames = len(self.frames)
if num_frames == 1:
self.canvas.itemconfig(self.image, image=self.frames[0])
else:
self.next_frame(0, num_frames)
def unload(self):
self.canvas.delete(self.image)
self.frames = None
def next_frame(self, loc, total):
if self.frames:
self.canvas.itemconfig(self.image, image=self.frames[loc])
loc = (loc + 1) % total
self.canvas.after(self.delay, self.next_frame, loc, total)
Then load it at specific position:
gif_window = tkinter_gif.ImageLabel(canvas)
gif_window.load("giphy.gif", -200, -200) # 0, 0 is the center of canvas
This is a function that creates an image:
def footgraph(self):
load = Image.open('centertext_out.png')
load= load.resize((500, 500), Image.ANTIALIAS)
render = ImageTk.PhotoImage(load)
self.img = Label( image=render)
self.img.image = render
self.img.place(x=150, y=5)
self.scale = tk.Scale(self.win, variable=self.value, orient="horizontal",length = 200,
from_=self.df['index'].unique().min(), to=self.df['index'].unique().max(), resolution =1,command=self.updateScaleFoot)
self.scale.place(x=250, y = 500)
self.stop.pack(expand='true',fill='both')
self.stop.place(x=200, y =500)
self.play.pack(expand='true',fill='both')
self.play.place(x=150, y = 500)
Here is a code for play button that keeps updating image:
while True:
self.index += 1
#update image(centertext_out.png) and save
load = Image.open('centertext_out.png')
load= load.resize((500, 500), Image.ANTIALIAS)
render = ImageTk.PhotoImage(load)
img = Label( image=render)
img.image = render
img.place(x=150, y=5)
time.sleep(10)
This loop is working fine. Self.index keeps updating. But image is not updating and screen hangs.
Edit:
When I use slider new image gets appended to previous one like this :
Edit:
I have narrowed down the problem. Below is the code for play function. When I click bar graph and if for bar graph turns true then code runs smoothly but it doesnt seem to be working for the second statement even if I have nothing inside of it.
def startanimation(self):
self.pause = 0
print("pause"+ str(self.pause))
while True:
if self.pause == 1:
break
self.index = self.index +1
print ("scale is now %s" % (self.index))
if "bar" in self.graphtype:
#some code
#draw canvas
self.fig.canvas.draw()
self.fig.canvas.flush_events()
time.sleep(0.2)
if "foot" in self.graphtype:
print("inside")
time.sleep(0.2)
Edit:
Changed code according to one of the answers.
class Application:
def __init__(self, master):
self.win = master
self.geo = self.win.geometry
self.geo("800x800+400+400")
self.win['bg'] = "black"
####################################################some code
def startanimation(self):
self.pause = 0
print("pause"+ str(self.pause))
if "foot" in self.graphtype:
self.win.after(1,self.test)
def test(self):
print("hi")
self.pause = 0
guide = pd.read_csv("guide.csv")
print("hey")
self.index +=1
test is called only once. hey is printed only once
Solved: check this link
Python Tkinter after() Only Executing Once
My task is to display a webcam stream and its black&white stream in two different frames on a single GUI using Tkinter on python. I have seen some examples on google, but they are of images not videos as in the link here. Example of image display in 2 panes on a single GUI
I need exactly the same thing but for the real time video through my webcam.
Initial question:
"I am having issues in displaying multiple (2) windows for displaying video frames in a GUI using Tkinter in python. Please help me with a
code for this task."
The initial question mentioned 2 windows so here's a basic example on how to create multiple windows with tkinter:
#import tkinter as tk
import Tkinter as tk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
#super().__init__()
tk.Tk.__init__(self)
self.title("This is the MainWindow")
self._is_hidden = False
self.window1 = OtherWindow(self, title="window 1")
self.window2 = OtherWindow(self, title="window 2")
def toggle_hide(self):
if self._is_hidden:
self.iconify()
self.deiconify()
else:
self.withdraw()
self._is_hidden = not self._is_hidden
class OtherWindow(tk.Toplevel):
def __init__(self, master, *args, **kwargs):
#super().__init__(master)
tk.Toplevel.__init__(self, master)
if 'title' in kwargs:
self.title(kwargs['title'])
self.hide_main_button = tk.Button(self, text="Hide/Show MainWindow")
self.hide_main_button['command'] = self.master.toggle_hide
self.hide_main_button.pack()
if __name__ == '__main__':
root = MainWindow()
root.mainloop()
from ttk import *
import Tkinter as tk
from Tkinter import *
import cv2
from PIL import Image, ImageTk
import os
import numpy as np
global last_frame #creating global variable
last_frame = np.zeros((480, 640, 3), dtype=np.uint8)
global last_frame2 #creating global variable
last_frame2 = np.zeros((480, 640, 3), dtype=np.uint8)
global cap
cap = cv2.VideoCapture(1)
def show_vid(): #creating a function
if not cap.isOpened(): #checks for the opening of camera
print("cant open the camera")
flag, frame = cap.read()
frame = cv2.resize(frame,(400,500))
if flag is None:
print "Major error!"
elif flag:
global last_frame
last_frame = frame.copy()
global last_frame2
last_frame2 = frame.copy()
pic = cv2.cvtColor(last_frame, cv2.COLOR_BGR2RGB) #we can change the display color of the frame gray,black&white here
img = Image.fromarray(pic)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, show_vid)
def show_vid2():
pic2 = cv2.cvtColor(last_frame2, cv2.COLOR_BGR2GRAY)
img2 = Image.fromarray(pic2)
img2tk = ImageTk.PhotoImage(image=img2)
lmain2.img2tk = img2tk
lmain2.configure(image=img2tk)
lmain2.after(10, show_vid2)
if __name__ == '__main__':
root=tk.Tk() #assigning root variable for Tkinter as tk
lmain = tk.Label(master=root)
lmain2 = tk.Label(master=root)
#lmain.Frame= Frame(width=768, height=576)
#framex.grid(column=3,rowspan=2,padx=5, pady=5)
lmain.pack(side = LEFT)
lmain2.pack(side = RIGHT)
root.title("Fire Alarm Detector") #you can give any title
root.geometry("900x700+100+10") #size of window , x-axis, yaxis
exitbutton = Button(root, text='Quit',fg="red",command= root.destroy).pack(side = BOTTOM,)
show_vid()
show_vid2()
root.mainloop() #keeps the application in an infinite loop so it works continuosly
cap.release()
import tkinter
import PIL.Image
import PIL.ImageTk
import cv2
class App:
def __init__(self, window, video_source1, video_source2):
self.window = window
self.window.title("KEC MEDIA PLAYER")
self.video_source1 = video_source1
self.video_source2 = video_source2
self.photo1 = ""
self.photo2 = ""
# open video source
self.vid1 = MyVideoCapture(self.video_source1, self.video_source2)
# Create a canvas that can fit the above video source size
self.canvas1 = tkinter.Canvas(window, width=500, height=500)
self.canvas2 = tkinter.Canvas(window, width=500, height=500)
self.canvas1.pack(padx=5, pady=10, side="left")
self.canvas2.pack(padx=5, pady=60, side="left")
# After it is called once, the update method will be automatically called every delay milliseconds
self.delay = 15
self.update()
self.window.mainloop()
def update(self):
# Get a frame from the video source
ret1, frame1, ret2, frame2 = self.vid1.get_frame
if ret1 and ret2:
self.photo1 = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(frame1))
self.photo2 = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(frame2))
self.canvas1.create_image(0, 0, image=self.photo1, anchor=tkinter.NW)
self.canvas2.create_image(0, 0, image=self.photo2, anchor=tkinter.NW)
self.window.after(self.delay, self.update)
class MyVideoCapture:
def __init__(self, video_source1, video_source2):
# Open the video source
self.vid1 = cv2.VideoCapture(video_source1)
self.vid2 = cv2.VideoCapture(video_source2)
if not self.vid1.isOpened():
raise ValueError("Unable to open video source", video_source1)
#property
def get_frame(self):
ret1 = ""
ret2 = ""
if self.vid1.isOpened() and self.vid2.isOpened():
ret1, frame1 = self.vid1.read()
ret2, frame2 = self.vid2.read()
frame1 = cv2.resize(frame1, (500, 500))
frame2 = cv2.resize(frame2, (500, 500))
if ret1 and ret2:
# Return a boolean success flag and the current frame converted to BGR
return ret1, cv2.cvtColor(frame1, cv2.COLOR_BGR2RGB), ret2, cv2.cvtColor(frame2, cv2.COLOR_BGR2RGB)
else:
return ret1, None, ret2, None
else:
return ret1, None, ret2, None
# Release the video source when the object is destroyed
def __del__(self):
if self.vid1.isOpened():
self.vid1.release()
if self.vid2.isOpened():
self.vid2.release()
def callback():
global v1,v2
v1=E1.get()
v2=E2.get()
if v1 == "" or v2 == "":
L3.pack()
return
initial.destroy()
v1 = ""
v2 = ""
initial = tkinter.Tk()
initial.title("KEC MEDIA PLAYER")
L0 = tkinter.Label(initial, text="Enter the full path")
L0.pack()
L1 = tkinter.Label(initial, text="Video 1")
L1.pack()
E1 = tkinter.Entry(initial, bd =5)
E1.pack()
L2 = tkinter.Label(initial, text="Video 2")
L2.pack()
E2 = tkinter.Entry(initial, bd =5)
E2.pack()
B = tkinter.Button(initial, text ="Next", command = callback)
B.pack()
L3 = tkinter.Label(initial, text="Enter both the names")
initial.mainloop()
# Create a window and pass it to the Application object
App(tkinter.Tk(),v1, v2)
This code works under normal circumstances but I haven't handled situations where one video ends and the other is still playing. Also, the audio has not been handled in this code.
I created two canvases in the same window and ran the video as a series of images. I have resized the video to fit a constant canvas size but you can change the canvas size to fit the video if you want.
You can change the source to be from your webcam.
I'm trying to implement simple image viewer, where you can choose from 2 pictures. I have one menubutton which offers these pictures. After choosing one of the images, the program creates 3 or 5 buttons. I would like to append to each of these buttons different images, so the first button would have one image and the second button would have another image and so on. I've created a function with for loop to create these buttons, but can't move on from that point. I can append one image to all of them, but can't do that one by one with different images.
Thanks for help
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
from functools import partial
from PIL import Image, ImageTk
class Halabala():
def __init__(self):
self.master = tk.Tk()
self.master.geometry("1100x700")
self.lists_labels = []
self.rbutton = tk.Menubutton(self.master, text = "Choose picture")
self.picks2 = tk.Menu(self.rbutton)
self.rbutton.config(menu=self.picks2)
self.picks2.add_command(label = "Spider", command = partial(self.create_labels,3))
self.picks2.add_command(label = "Sugar", command = partial(self.create_labels,5))
self.rbutton.config(width = 30, bg = "white", bd = 5, relief = tk.RAISED)
self.rbutton.place(x = 900, y = 30)
self.master.mainloop()
def create_labels(self, num):
self.picture = Image.open("blue.gif")
self.picture.thumbnail((130,130))
self.tkim = ImageTk.PhotoImage(self.picture)
for label in self.lists_labels:
label.destroy()
self.lists_labels=[]
for i in range(num):
but = tk.Button(self.master, image = self.tkim)
but.grid(row = i + 1, column = 0)
self.lists_labels.append(but)
myapp = Halabala()
This is the code relevant for your question:
class Halabala():
def __init__(self):
.............
self.pictures = ["pavuk1", "pavuk2", "pavuk3"]
self.lists_labels = []
self.lists_images = []
self.init_image_list()
............
def init_image_list(self):
for i in self.pictures:
picture = Image.open(i)
picture.thumbnail((130, 130))
self.lists_images.append(ImageTk.PhotoImage(picture))
def create_labels(self, num):
for label in self.lists_labels:
label.destroy()
self.lists_labels=[]
for i in range(num):
but = tk.Button(self.master, image = self.lists_images[i])
but.grid(row = i + 1, column = 0)
self.lists_labels.append(but)