How to make a timer?

Hi all,

I would like to integrate a countdown in my app - say from 5 minutes to zero, updating every second.

I can reload the app every second and maybe save the initial timestamp in memory to print the difference but this is not ideal for obvious reasons.
Do you see a better approach?

thanks

Hi!

You could use the metrics and display a countdown:

import streamlit as st
import time

st.set_page_config()

ph = st.empty()
N = 5*60
for secs in range(N,0,-1):
    mm, ss = secs//60, secs%60
    ph.metric("Countdown", f"{mm:02d}:{ss:02d}")
    time.sleep(1)

countdown

But there is a huge catch: the app wont be able to do anything else until the countdown ends (It stays on the countdown loop). Iā€™d love to know if thereā€™s a way to avoid this!

4 Likes

Hi @sebastiandres , I think you should be able to get out of a for loop by using an if condition with a break statement (just above your time.sleep command). You could probably even check for an Escape keypress using some of the available python libraries (pyautogui, keyboard, etc.).

I havenā€™t tried it out, but here seems an example of a break from a while loop. https://www.delftstack.com/howto/python/python-detect-keypress/

Cheers

1 Like

Thanks @sebastiandres , it is an interesting solution.

As you pointed out, the app cannot do anything else and thatā€™s a problem. Iā€™ll try to combine it with a break option and Iā€™ll save the countdown starting time to resume the countdown consistently when any other interaction with the app is done.

Another option would be to have the countdown in pure javascript+html (no streamlit), but you would need some knowledge to make it look good. A bare bones version could be:

import streamlit as st
from streamlit.components.v1 import html
import time

st.set_page_config()

my_html = """
<script>
function startTimer(duration, display) {
    var timer = duration, minutes, seconds;
    setInterval(function () {
        minutes = parseInt(timer / 60, 10)
        seconds = parseInt(timer % 60, 10);

        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;

        display.textContent = minutes + ":" + seconds;

        if (--timer < 0) {
            timer = duration;
        }
    }, 1000);
}

window.onload = function () {
    var fiveMinutes = 60 * 5,
        display = document.querySelector('#time');
    startTimer(fiveMinutes, display);
};
</script>

<body>
  <div>Registration closes in <span id="time">05:00</span> minutes!</div>
</body>
"""

html(my_html)


if st.button("Is blocked?"):
  st.write("No, you can still interact")
  st.balloons()

(Not my javascript, I googled and copied the first result of javascript countdown)

3 Likes

You can also create an external asyncio thread managing the timer for you :slight_smile:

2 Likes

This async solution is very solid. Thanks

1 Like

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.