-1

I need to implement a countdown timer in python. I tried this, but the program get stuck and I have to do a forced quit. For the same reason, I can't have an infinitive loop into the run() method. How can I do?

class th(Thread):
    def __init__(self):
        Thread.__init__(self)

    def run(self):
        printer()

def printer():
    print(time.time()*1000.0)
    time.sleep(1)
    printer()

thread1 = th()
thread1.start()
Lorenzo
  • 47
  • 8
  • can you show the complete code? – Alihossein shahabi May 29 '18 at 08:05
  • 1
    "The program crashes" is not an acceptable problem description. – timgeb May 29 '18 at 08:05
  • 1
    How does it crash? Why are you inheriting Thread? You can use threading without making your own class – pdowling May 29 '18 at 08:05
  • 1
    Change the recursive call to a while loop – cs95 May 29 '18 at 08:06
  • How is that supposed to be a countdown timer? It counts up! BTW, [`time.time`](https://stackoverflow.com/questions/41777880/functions-that-help-to-understand-jsondict-structure) is _not_ intended for use as a high precision timing function. See [time.perf_counter](https://docs.python.org/3/library/time.html#time.perf_counter). – PM 2Ring May 29 '18 at 08:13
  • @coldspeed I said I can't use while loop because the program get stuck and I have to do a force quit. – Lorenzo May 29 '18 at 08:48
  • @PM2Ring you're right but it doesn't mind. The point is how to do an action every x milliseconds with an high precision – Lorenzo May 29 '18 at 08:49
  • Ok. It looks like your real question is how to make a timer that you can close gracefully, without a force quit. That information should go in your question. But you still need to get rid of that recursion. – PM 2Ring May 29 '18 at 08:52
  • Which OS do you want to do this on? – PM 2Ring May 29 '18 at 09:00
  • A simple way to do this is to use a GUI. Eg, https://stackoverflow.com/a/44372709/4014959 – PM 2Ring May 29 '18 at 09:24

1 Answers1

0

You didn't say which OS you're using, so I'll assume that you're using a system with a standard ANSI/VT100 terminal, so we can use ANSI escape sequences to move the cursor, etc. If you're using a non-standard OS these sequences may not work in your terminal.

This program displays the number of seconds since the program was launched, at the top of the terminal window. The time display is updated every 0.1 seconds. Beneath the time display there's an input prompt, which waits for the user to close the program.

from time import perf_counter
from threading import Timer

# Some ANSI/VT100 Terminal Control Escape Sequences
CSI = '\x1b['
CLEAR = CSI + '2J'
CLEAR_LINE = CSI + '2K'
SAVE_CURSOR = CSI + 's'
UNSAVE_CURSOR = CSI + 'u'
GOTO_LINE = CSI + '%d;0H'

def emit(*args):
    print(*args, sep='', end='', flush=True)

start_time = perf_counter()
def time_since_start():
    return '{:.6f}'.format(perf_counter() - start_time)

def show_time(interval):
    global timer
    emit(SAVE_CURSOR, GOTO_LINE % 1, CLEAR_LINE, time_since_start(), UNSAVE_CURSOR)
    timer = Timer(interval, show_time, (interval,))
    timer.start()

# Set up scrolling, leaving the top line fixed
emit(CLEAR, CSI + '2;r', GOTO_LINE % 2)

# Start the timer loop
show_time(interval=0.1)

input('Press Enter to stop the timer:')
timer.cancel()

# Cancel scrolling
emit('\n', SAVE_CURSOR, CSI + '0;0r', UNSAVE_CURSOR)

This code was derived from this previous answer of mine.


Here's a more primitive version, with no cursor control, apart from using the '\r' Carriage Return control character, which should work on any system. You probably don't need the flush=True arg to print, depending on your terminal.

from time import time as perf_counter
from threading import Timer

start_time = perf_counter()

def show_time(interval):
    global timer
    print('  {:.6f}'.format(perf_counter() - start_time), end='\r', flush=True)
    timer = Timer(interval, show_time, (interval,))
    timer.start()

# Start the timer loop
show_time(interval=0.1)

input(15 * ' ' + ': Press Enter to stop the timer.\r')
timer.cancel()
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182