Home > other >  How can I create a new image over an existing one with Pillow after 20 seconds, repeatedly?
How can I create a new image over an existing one with Pillow after 20 seconds, repeatedly?

Time:11-24

I'm trying to make a little elevator pitch program as a way to present myself. The program counts down from 2 minutes, and I'd like it to automatically update with a picture every 20 seconds. This allows me to give details about the shown picture for 20 seconds, and then move on.

However, I am stuck on the image switching part. I've looked at .after(), .time(), .sleep() and looked at threading - which is still an unknown and rough concept for me.

So far, this is where I am at.

Currently, my thoughts are all over the place and I'm not sure which way would work (best). I've considered a nested if-statement inside the countdown function, but that would make everything very hard to read, I think.

I've considered setting up a second function which would handle the image changing, of which you can see an early and not working example below.


from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk
import math
import time
import datetime


# ---------------------------- CONSTANTS ------------------------------- #
PINK = "#e2979c"
RED = "#e7305b"
GREEN = "#9bdeac"
YELLOW = "#f7f5dd"
BLUE = "#678ac2"
FONT_NAME = "Courier"
REPEATS = 0

# ---------------------------- TIMER MECHANISM ------------------------------- #


def countdown(total_seconds=60, total_minutes=2):
    if total_seconds == 60:
        total_seconds -= 1
        total_minutes -= 1
        timer_text.config(text=f"{total_minutes}:{total_seconds}")
        window.after(1000, countdown, total_seconds, total_minutes)
    elif total_seconds == 1 and total_minutes != 0:
        total_seconds  = 59
        timer_text.config(text=f"{total_minutes}:00")
        window.after(1000, countdown, total_seconds, total_minutes)
    elif total_seconds == 0 and total_minutes > 0:
        total_seconds = 59
        total_minutes -= 1
        timer_text.config(text=f"{total_minutes}:{total_seconds}")
        window.after(1000, countdown, total_seconds, total_minutes)
    elif 11 > total_seconds > 0:
        total_seconds -= 1
        timer_text.config(text=f"{total_minutes}:0{total_seconds}")
        window.after(1000, countdown, total_seconds, total_minutes)
    elif total_seconds == 0 and total_minutes == 0:
        pass
    else:
        total_seconds -= 1
        timer_text.config(text=f"{total_minutes}:{total_seconds}")
        window.after(1000, countdown, total_seconds, total_minutes)


def image_change():
    global REPEATS
    REPEATS  = 1
    if REPEATS == 1:
        second_img = (Image.open("edward.png"))
        second_resized_image = second_img.resize((850, 450), Image.LANCZOS)
        second_new_image = ImageTk.PhotoImage(second_resized_image)
        canvas.create_image(450, 225, anchor=CENTER, image=second_new_image)
    elif REPEATS == 2:
        print("repeats worked once")
    else:
        print("Error with repeats")


# ---------------------------- UI SETUP ------------------------------- #

# Create window & canvas


window = Tk()
window.title("Elevator Pitch")
window.geometry("900x600")
window.configure(bg=BLUE)

canvas = Canvas(window, width=900, height=500, bg=BLUE)
canvas.grid(column=1, row=1)

img = (Image.open("paco.png"))
resized_image = img.resize((850, 450), Image.LANCZOS)
new_image = ImageTk.PhotoImage(resized_image)
canvas.create_image(450, 225, anchor=CENTER, image=new_image)


# Create timer text & button


timer_text = Label(window, text="2:00", font=(FONT_NAME, 35, "bold"), bg=BLUE)
timer_text.grid(column=1, row=2)

start_button = Button(text="Start", command=countdown)
start_button.grid(column=1, row=3)

# Create new images


window.mainloop()


CodePudding user response:

You can change the image when the countdown is divisible by 20 seconds. I've simplified your countdown so it just uses the number of seconds to make this easier. I've added the load_image function to delete the existing image if there is one and then show the next one. It uses pop to get and remove the first images from the IMAGES array.

from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk
import math
import time
import datetime

# ---------------------------- CONSTANTS ------------------------------- #
PINK = "#e2979c"
RED = "#e7305b"
GREEN = "#9bdeac"
YELLOW = "#f7f5dd"
BLUE = "#678ac2"
FONT_NAME = "Courier"
# Changes start here
IMAGES = ["first.png", "second.png", "third.png", ...] # Put your image file paths here
CURRENT_IMAGE = None
CURRENT_PHOTOIMAGE = None

# ---------------------------- TIMER MECHANISM ------------------------------- #

def countdown(total_seconds=120):
    total_seconds -= 1
    minutes, seconds = divmod(total_seconds, 60)
    timer_text.config(text = f"{minutes}:{seconds:02d}")
    if total_seconds % 20 == 0 and IMAGES: # Will be called every 20 seconds if there are any images left
        load_image()
    if total_seconds > 0:
        window.after(1000, countdown, total_seconds)


def load_image():
    global CURRENT_IMAGE, CURRENT_PHOTOIMAGE
    if IMAGES:
        if CURRENT_IMAGE:
            canvas.delete(CURRENT_IMAGE)
        img = Image.open(IMAGES.pop(0))
        resized_image = img.resize((850, 450), Image.LANCZOS)
        # It's important to keep a reference to the PhotoImage or it'll get garbage collected
        CURRENT_PHOTOIMAGE = ImageTk.PhotoImage(resized_image)
        CURRENT_IMAGE = canvas.create_image(450, 225, anchor=CENTER, image=CURRENT_PHOTOIMAGE)


# ---------------------------- UI SETUP ------------------------------- #

# Create window & canvas


window = Tk()
window.title("Elevator Pitch")
window.geometry("900x600")
window.configure(bg=BLUE)

canvas = Canvas(window, width=900, height=500, bg=BLUE)
canvas.grid(column=1, row=1)

load_image()
# Changes end here
timer_text = Label(window, text="2:00", font=(FONT_NAME, 35, "bold"), bg=BLUE)
timer_text.grid(column=1, row=2)

start_button = Button(text="Start", command=countdown)
start_button.grid(column=1, row=3)

# Create new images


window.mainloop()
  • Related