How can I activate a new gif, have it play for 5 seconds, then return to the previous gif in Python?

Viewed 37

I am working on a simple application using PySimpleGUI that shows a gif character in an "idle" animation and want to be able to change to a different gif animation when hitting a button, have the animation play for 5 seconds, then automatically switch back to the "idle" animation. I have been able to complete all of the above aside from the "play for 5 seconds, then automatically switch back to the 'idle' animation" piece.

Here is the code thus far:

import PySimpleGUI as sg

# storing gifs as base64 
idle = b'[base64 encoded gif]'
wave = b'[base64 encoded gif]'
cheer = b'[base64 encoded gif]'
tipjar = b'[base64 encoded gif]'
cocktail = b'[base64 encoded gif]'
beer = b'[base64 encoded gif]'

# Putting all gifs into a list
gifs = [idle, wave, cheer, tipjar, cocktail, beer]

# Setting up the window and button layout
sg.theme('DarkAmber')

layout = [[sg.Image(background_color='#00b140', key='-IMAGE-', pad=(0, 0), right_click_menu=[
                    '&Right', ['Settings', 'Exit']])],
          [sg.Button('!Wave'), sg.Button('!Cheer'), sg.Button('!TipJar'), sg.Button('!Cocktail'), sg.Button('!Beer')]]

window = sg.Window('Animated Avatar', layout, margins=(0, 0), finalize=True)
image = window['-IMAGE-']

# Calling the first item in the gifs list
gif = gifs[0]

# Program loop
while True:
    event, values = window.read(timeout=100)
    if event == sg.WIN_CLOSED or event == 'Exit':
        break

    # Button click events to change the gif being presented
    elif event == '!Wave':
        gif = gifs[1]

    elif event == '!Cheer':
        gif = gifs[2]

    elif event == '!TipJar':
        gif = gifs[3]

    elif event == '!Cocktail':
        gif = gifs[4]

    elif event == '!Beer':
        gif = gifs[5]

    # Overall gif animation rules
    image.update_animation(gif, 500)

How can I complete the 5 second gif animation and return to idle?

2 Answers

I have solved my question. I used perf_counter() as a timer which counts up from zero. Once it hits a set integer, the gif is changed back to the "idle" animation. Each time a button is activated, the timer is reset to zero to count back up.

# Calling the first item in the gifs list and setting up a timer variable
gif = gifs[0]
timer = time.perf_counter()

# Program loop
while True:

    # Make the timer count up and change back to idle gif when 5 seconds elapses
    elapsed = (time.perf_counter() - timer)
    if elapsed >= 5:
        gif = gifs[0]
        timer = time.perf_counter()

    # Button click events to change the gif being presented and reset counter to zero
    elif event == '!Wave':
        timer = time.perf_counter()
        gif = gifs[1]

    elif event == '!Cheer':
        gif = gifs[2]
        timer = time.perf_counter()

If anyone has a better way to do it or suggestions on how to clean up my code please let me know.

There're something wrong to view some GIF at this moment, so I add code here to open GIF by PIL.Image/PIL.ImageTk/PIL.ImageSequence.

It may take time to download GIFs from website and get each frame from GIF, you can do it before script running to save the time.

import base64
import pathlib
import requests
from PIL import Image, ImageTk, ImageSequence
import PySimpleGUI as sg

sg.popup_non_blocking("Wait for gif data ready ...", auto_close=True, auto_close_duration=2)

urls = {
    "Hi Baby":'https://bobble-animations.bobblekeyboard.net/previews/animation_preview_b87c9d99-d0a5-4d86-821b-4bf4d69765b1.gif',
    "Are You Serious":'https://bobble-animations.bobblekeyboard.net/previews/animation_preview_461fed8b-ee94-46bd-bfbf-4047bee4b615.gif',
    "Miss You":'https://bobble-animations.bobblekeyboard.net/previews/animation_preview_d8155620-10c0-4a48-b143-fb35d700fe80.gif',
    "I'm Borke":'https://bobble-animations.bobblekeyboard.net/previews/animation_preview_d79a57bd-c183-44fa-8969-ee710e766de7.gif',
    "I Kill You":'https://bobble-animations.bobblekeyboard.net/previews/animation_preview_f6178668-2bc7-4039-ae95-4d1815a3a554.gif',
    "Call Me":'https://bobble-animations.bobblekeyboard.net/previews/animation_preview_11f15a3f-eb9f-4cec-a799-8c6e882b182d.gif',
    "Oh My God":'https://bobble-animations.bobblekeyboard.net/previews/animation_preview_0edf207c-8189-411f-b745-5b90f92cb37d.gif',
}
idle = "Hi Baby"

for key, url in urls.items():
    filename = f'{key}.gif'
    if not pathlib.Path(filename).is_file():
        with open(filename, 'wb') as f:
            f.write(requests.get(urls[key]).content)

# --Following code should be called after window finalized or sg.popup called.--
gifs = {}
for key, url in urls.items():
    filename = f'{key}.gif'
    images = [ImageTk.PhotoImage(frame) for frame in ImageSequence.Iterator(Image.open(filename))]
    gifs[key] = (len(images), images)
# ------------------------------------------------------------------------------

sg.theme('DarkBlue3')
layout = [
    [sg.Image(filename=f'{idle}.gif', key='-IMAGE-')],
    [sg.Button(key, expand_x=True) for key in urls if key !=idle],
]
window = sg.Window('Animation', layout, margins=(0, 0), finalize=True)
image = window['-IMAGE-']

show, gif, index, frames, count = idle, gifs[idle][1], 0, len(gifs[idle][1]), 0

while True:

    event, values = window.read(timeout=100)

    if event == sg.WIN_CLOSED:
        break

    elif event in gifs:
        gif, index, frames, count = gifs[event][1], 0, len(gifs[event][1]), 0

    elif event == sg.TIMEOUT_EVENT:
        count += 1
        if count == 20: # 2 seconds
            show, gif, index, frames, count = idle, gifs[idle][1], 0, len(gifs[idle][1]), 0
        image.update(data=gif[index])
        index = (index + 1) % frames

window.close()

enter image description here

Related