Search code examples
pythonmultithreadingtimercountdown

python add time to a countdown already running


I want to have an app where if I click a button I add X amount of time to my running countdown timer.

I'm guessing I have to use threads for this but am not sure how to implement it..

Here is the code I have so far:

def countdown_controller(add_time):
    end_it = False
    def timer(time_this):
        start = time.time()
        lastprinted = 0
        finish = start + time_this
        while time.time() < finish:
            now = int(time.time())
            if now != lastprinted:
                time_left = int(finish - now)
                print time_left
                lastprinted = now
            if end_it == True:
                now = finish
            time.sleep(0.1)
    # Check if the counter is running otherwise just add time.
    try:
        time_left 
    except NameError:
        timer(add_time)
    else:
        if time_left == 0:
        timer(add_time)
        else:
            add_this = time_left
            end_it = True
            while now != finish:
                time.sleep(0.1)
            timer(add_time + add_this)

Obviously this will not work, because every time I call countdown_controller(15) fx, it will start counting down for 15 seconds and if I click my button nothing happens until the timer is ended.

Help would be greatly appreciated.


Solution

  • I would say that there is a flaw in the design of the code, because your screen output blocks down the entire program doing nothing (time.sleep(0.1)).

    Typically what you want to to do in these cases is having a main loop in your program that cycles through the various operations that make your program run. This guarantees a sensible distribution of system resources between the various tasks.

    In your specific case, what you would like to have in your main loop is:

    • Check user input (has extra time been added?)
    • Update output of the countdown

    Example implementation:

    import time
    import curses
    
    # The timer class    
    class Timer():
        def __init__(self):
            self.target = time.time() + 5
        def add_five(self):
            self.target += 5
        def get_left(self):
            return int(self.target-time.time())
    
    # The main program
    t = Timer()
    stdscr = curses.initscr()
    stdscr.nodelay(True)
    curses.noecho()
    # This is the main loop done in curses, but you can implement it with
    # a GUI toolkit or any other method you wish.
    while True:
        left = t.get_left()
        if left <= 0:
            break
        stdscr.addstr(0, 0, 'Seconds left: %s ' % str(left).zfill(3))
        c = stdscr.getch()
        if c == ord('x') :
            t.add_five()
    # Final operations start here
    stdscr.keypad(0)
    curses.echo()
    curses.endwin()
    print '\nTime is up!\n'
    

    The above program will increase the counter of 5 seconds if you press the x key (lowercase). Most of the code is boilerplate to use the curses module, but of course if you use PyGTK, PySide or any other graphical toolkit, it will be different.

    EDIT: As a rule of thumb, in python you want to avoid threading as much as you can, both because it often (but not always) slows down programs (see "Global Interpreter Lock") and because it makes software harder to debug/maintain.

    HTH!