Python tkinter time delay before placing/ removing images - python

I have created a python tkinter program, where I want to display a series of images on a window, where the image changes every 6 seconds. When I use the code below, the whole program freezes for the entire 6 seconds.
loopey = "Fal"
while loopey == "Fal":
time.sleep(6)
menupic.place_forget()
menupic2.place(x=602,y=180)
home.update()
time.sleep(6)
menupic2.place_forget()
menupic.place(x=602,y=180)
home.update()
I also tried to use the after() function, but had the same issue.
def deletion(thing):
thing.place_forget()
while True:
home.after(6000, deletion(menupic))
menupic2.place(x=602,y=180)
home.update()
home.after(6000, deletion(menupic2))
menupic.place(x=602,y=180)
home.update()

I would do it like this:
from tkinter import *
from PIL import Image, ImageTk
from random import randint
import numpy as np
def place_image():
npimg = np.zeros([100,100,3],dtype=np.uint8)
npimg.fill(randint(0, 255))
pilimg = Image.fromarray(npimg)
tkimg = ImageTk.PhotoImage(pilimg)
label.img = tkimg
label.configure(image=tkimg)
home.after(6000, place_image)
home = Tk()
label = Label(home, text="test")
label.place(x=0, y=0)
home.after(6000, place_image)
home.mainloop()
If you use after() also in the function you can still interact with the window.
It wil still loop trought every 6 seconds.

Related

How can you run two python tkinter files simultaneously when one has a loop in it?

I have made a tkinter country guessing game witch works fine however takes along time to run. So i made a loading screen for it with a looping animation on in a separate file. I cant find a way to run the loading screen first and then run the game whilst the animation on the loading screen is still running.
Loading screen code:
from tkinter import *
from time import *
import os
import random
run = 0
loads = True
dotnum = 0
def task():
sleep(2)
root.destroy()
root = Tk()
root.title("Loading...")
root.geometry("1280x720")
Background = PhotoImage(file = "Images\Loadscreen.png")
Loaders = PhotoImage(file = "Images\Loader.gif")
image = Label(root,width=1000,height=500,image=Background)
image.place(x=0, y=0, relwidth=1, relheight=1)
frameCnt = 16
frames = [PhotoImage(file='Images\Loader.gif',format = 'gif -index %i' %(i)) for i in range(frameCnt)]
def update(ind):
frame = frames[ind]
ind += 1
if ind == frameCnt:
ind = 0
loadanim.configure(image=frame)
root.after(100, update, ind)
loadanim = Label(root, bg = "black")
loadanim.place(x = 450, y = 450)
root.after(0, update, 0)
root.mainloop()
To run the loading screen first, you can call the loading screen code before calling the game code.
You can modify the code to pass a function as an argument to the loading screen, and then call this function after the loading screen is destroyed. This will allow you to run the game code after the loading screen is done.
For example:
def run_game():
# game code here
pass
def run_loading_screen(callback):
# loading screen code here
root.after(2000, callback)
root.mainloop()
run_loading_screen(run_game)
Here, run_game is the function containing the game code, and run_loading_screen is the function containing the loading screen code. The run_loading_screen function takes a callback argument, which is the function to be called after the loading screen is destroyed. In the loading screen code, the root.after method is used to call the callback function after 2000 milliseconds (2 seconds).

How to rotate a image in Python tkinter Window

I am working on a python messaging application using tkinter and i need a loading screen animation but none of them where fitting with my purpose so i Tried to rotate a image in python continusly which will look like a animation.
This is the image i want to ratate for some time in tkinter
The application code
i only need a simple tkinter window with the rotating screen
I tried google and i got this code to rote a image
from PIL import Image # Import Image class from the library.
image = Image.open("file.jpg") # Load the image.
rotated_image = image.rotate(180) # Rotate the image by 180 degrees.
rotated_image.save("file_rotated.jpg")
So i tried using this code like this:-
from tkinter import *
from PIL import ImageTk, Image
import os
root = Tk()
c = Canvas(root, width=700, height=700)
c.pack()
while True:
img = ImageTk.PhotoImage(Image.open(r"Loading_Icon.png"))
c.create_image(100, 100, image=img, anchor=NW)
image = Image.open(Loading_Icon.png") # Load the image.
rotated_image = image.rotate(30)
os.remove("Loading_Icon.png")
rotated_image.save("Loding_Icon.png")
root.mainloop()
c.delete("all")
Look at this:
from PIL import Image, ImageTk
import tkinter as tk
# Load the original image
pil_img = Image.open("pawn.black.png")
def loading_loop(i=0):
global tk_img
print(f"Loop {i}")
# If the prgram has loaded, stop the loop
if i == 13: # You can replace this with your loading condition
return
# Rotate the original image
rotated_pil_img = pil_img.rotate(30*i)
tk_img = ImageTk.PhotoImage(rotated_pil_img)
# put the rotated image inside the canvas
canvas.delete("all")
canvas.create_image(0, 0, image=tk_img, anchor="nw")
# Call `loading_loop(i+1)` after 200 milliseconds
root.after(200, loading_loop, i+1)
root = tk.Tk()
canvas = tk.Canvas(root)
canvas.pack()
# start the tkinter loop
loading_loop()
root.mainloop()
It loads the original image then it start a tkinter loop which runs loading_loop every 200 milliseconds. Inside loading_loop, I rotate the image 30*i degrees, where i is the iteration number. Then I put the image inside the canvas.
Notice how I only call .mainloop() once and there is no while True loop. Those are best practises for when using tkinter.
It's best to create only 1 image inside the canvas and just reconfigure it but that will make the code longer.

Slide show program, event processing

I need the images to change if the cursor is inside the window without moving, but I managed to make the image changes only if the cursor is moving inside the window, how can I change the code?
from itertools import cycle
import tkinter as tk
from PIL import ImageTk, Image
import glob
image_files = glob.glob("*.jpg")
root = tk.Toplevel()
root.geometry("1600x900")
pictures = cycle((ImageTk.PhotoImage(file=image), image) for image in image_files)
picture_display = tk.Label(root)
picture_display.pack()
def show_slides(event):
img_object, img_name = next(pictures)
root.after(500, picture_display.config(image=img_object))
root.bind("<Motion>", show_slides)
root.mainloop()
You could bind the <Enter> and <Leave> events and use a flag to control the call, followed by using the after method to loop the function.
def show_slides(event=None):
global change_slide
img_object, img_name = next(pictures)
picture_display.config(image=img_object)
change_slide=root.after(500,show_slides)
def stop_slides(event):
root.after_cancel(change_slide)
root.bind("<Enter>", show_slides)
root.bind("<Leave>", stop_slides)
UPDATE
Using a flag might cause multiple calls being scheduled it the events happen during the 500ms delay, you can use after_cancel to terminate it.
You can calculate cursor position in loop and show image if it's located within tkinter window:
import glob
import tkinter as tk
from PIL import ImageTk
from itertools import cycle
class App(object):
def __init__(self):
self.root = tk.Tk()
self.root.geometry('900x600')
self.lbl = tk.Label(self.root)
self.lbl.pack()
files = glob.glob('*.jpg')
self.images = cycle((ImageTk.PhotoImage(file=f), f) for f in files)
self.show()
self.root.mainloop()
def show(self):
abs_coord_x = self.root.winfo_pointerx() - self.root.winfo_rootx()
abs_coord_y = self.root.winfo_pointery() - self.root.winfo_rooty()
if 0 <= abs_coord_x <= self.root.winfo_width() and 0 <= abs_coord_y <= self.root.winfo_height():
img_object, img_name = next(self.images)
self.lbl.config(image=img_object)
self.root.after(1000, self.show)
App()

Can't move image with time delay

I'm trying to figure out how to make a scrolling image in python, but I got into some issues with delay. I need the image to move after the canvas has rendered, and I also need it to move with a time delay. Here is my current code:
from Tkinter import *
import ImageTk
import time
def scrollToTop(imaget):
for x in range(100, 20, -1):
canvas.move(imaget, 0, -1)
t = Tk()
canvas = Canvas(t,height=256,width=256)
canvas.pack()
arrows = [1]
arrows[0] = ImageTk.PhotoImage(file="arrow.bmp")
image = canvas.create_image(20,100,image=arrows[0],tags="token")
t.mainloop();
scrollToTop(image);
I tried playing around where the scrollToTop() function was, and I also tried time.delay(0.1), all to no avail. I could try something like an Update() function, that measures the time passed from a "game time" variable...
Thanks in advance!
First: main loop t.mainloop() run till you close program so every instruction after t.mainloop() will be run after you close program.
You can use timer to call scrollToTop (for example) every 1 second (1000 millisecond)
from Tkinter import *
import ImageTk
import time
def scrollToTop():
print "I'm in scrollToTop()"
canvas.move(image, 0, -1)
t.after(1000, scrollToTop)
t = Tk()
canvas = Canvas(t,height=256,width=256)
canvas.pack()
arrows = [1]
arrows[0] = ImageTk.PhotoImage(file="arrow.bmp")
image = canvas.create_image(20,100,image=arrows[0],tags="token")
scrollToTop()
t.mainloop();
EDIT:
t.after() require function name without () so if you need to run functiion with arguments use lambda function
from Tkinter import *
import ImageTk
import time
def scrollToTop(imaget):
print "I'm in scrollToTop()"
canvas.move(imaget, 0, -1)
t.after(1000, lambda:scrollToTop(imaget))
t = Tk()
canvas = Canvas(t,height=256,width=256)
canvas.pack()
arrows = [1]
arrows[0] = ImageTk.PhotoImage(file="arrow.bmp")
image = canvas.create_image(20,100,image=arrows[0],tags="token")
scrollToTop(image)
t.mainloop();

Displaying and refreshing my picture every 5 seconds

Ok, I've got the GUI in tkinter working, and I'm trying to grab and image every 5 seconds and display it in a Label named Picturelabel.
from Tkinter import *
from PIL import ImageGrab
import cStringIO, base64, time, threading
class PictureThread(threading.Thread):
def run(self):
print "test"
box = (0,0,500,500) #x,x,width,height
MyImage = ImageGrab.grab(box)
fp = cStringIO.StringIO()
MyImage.save(fp, 'GIF')
MyPhotoImage = PhotoImage(data=base64.encodestring(fp.getvalue()))
time.sleep(5)
PictureThread().run() #If I get rid of this then it just display one image
return MyPhotoImage
MyVeryNewImage = PictureThread().run()
Picturelabel = Label(BalanceFrame, image=MyVeryNewImage)
Picturelabel.grid(row=3, column=2, columnspan=3)
Picturelabel.image = MyVeryNewImage
window.mainloop()
Firstly how can I clean up this code, as starting a thread inside another thread can't be good practice.
Also when I run this it prints "test" in the console, but it does not bring up the GUI.
If I comment out the commented text (PictureThread().run() where I'm creating yet another thread inside it.) then it displays the first image, but not any more.
You should call start() instead of run(). From the Documentation:
Once a thread object is created, its
activity must be started by calling
the thread’s start() method. This
invokes the run() method in a separate
thread of control.
I see you're invoking a new thread inside your run() method. This will cause you to spawn infinite threads!
EDIT: I'm not sure if this works:
from Tkinter import *
from PIL import ImageGrab
import cStringIO, base64, time, threading
Picturelabel = Label(BalanceFrame)
Picturelabel.grid(row=3, column=2, columnspan=3)
class PictureThread(threading.Thread):
def run(self):
print "test"
box = (0,0,500,500) #x,x,width,height
fp = cStringIO.StringIO()
while(1):
MyImage = ImageGrab.grab(box)
MyImage.save(fp, 'GIF')
self.image = PhotoImage(data=base64.encodestring(fp.getvalue()))
Picturelabel.image = self.image
fp.reset() # reset the fp position to the start
fp.truncate() # and truncate the file so we don't get garbage
time.sleep(5)
PictureThread().start()
window.mainloop()
The problem is that you return the new image from the PictureThread().run() in the method, but you never save it.
How about:
from Tkinter import *
from PIL import ImageGrab
import cStringIO, base64, time, threading
box = (0,0,500,500) #x,x,width,height
MyImage = ImageGrab.grab(box)
fp = cStringIO.StringIO()
MyImage.save(fp, 'GIF')
MyPhotoImage = PhotoImage(data=base64.encodestring(fp.getvalue()))
Picturelabel = Label(BalanceFrame, image=MyPhotoImage)
Picturelabel.grid(row=3, column=2, columnspan=3)
class PictureThread(threading.Thread):
def run(self):
while True:
box = (0,0,500,500) #x,x,width,height
MyImage = ImageGrab.grab(box)
fp = cStringIO.StringIO()
MyImage.save(fp, 'GIF')
MyPhotoImage = PhotoImage(data=base64.encodestring(fp.getvalue()))
time.sleep(5)
Picturelabel.image = MyPhotoImage
PictureThread().start()
window.mainloop()

Categories

Resources