制作一个“任意键”可插入的Python计时器

时间:2013-12-07 07:48:49

标签: python multithreading timer interrupt

我正在尝试制作一个简单的计时器,直到它被键盘输入中断为止。

现在我正在使用CTRL + C来停止计时器,但我想做一些更简单的事情,如点击空格或输入或“任何键”。我听说这可以通过线程模块完成,但经过多次尝试后我显然不知道我在做什么。

这是我目前的代码:

def countup():
    try:
        a=0
        for i in range(1000000) :
            print i,'\r',
            time.sleep(1)
    except KeyboardInterrupt:
         Z = raw_input("restart timer?" )
         if Z == "Y" or Z == "y" :
             countup()

2 个答案:

答案 0 :(得分:4)

使用threadterminal capabilities可以写(按任意键停止):

import thread
import time

def read_key():
    import termios
    import sys
    fd = sys.stdin.fileno()
    old = termios.tcgetattr(fd)
    new = termios.tcgetattr(fd)
    new[3] &= ~(termios.ICANON | termios.ECHO) # c_lflags
    c = None
    try:
        termios.tcsetattr(fd, termios.TCSANOW, new)
        c = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSANOW, old)
    return c

def input_thread():
    read_key()
    thread.interrupt_main()

def countup():
    try:
        thread.start_new_thread(input_thread, ())
        for i in range(1000000):
            print i
            time.sleep(1)
    except KeyboardInterrupt:
        Z = raw_input("restart timer? ")
        if Z == 'y' or Z == 'Y':
            countup()

让我们澄清一下:

thread.start_new_thread()使用input_thread()作为启动函数创建一个新线程。虽然thread.interrupt_main()在主线程中提升KeyboardInterrupt

termios.tcgetattr()返回当前终端属性。 ~termios.ICANON取消设置canonical模式,~termios.ECHO阻止输入打印,然后termios.tsetattr()执行更改。

或者,在Windows上,可以使用msvcrt中的getch()代替read_key()

def input_thread():
    msvcrt.getch()
    thread.interrupt_main()

参考

答案 1 :(得分:0)

您的代码有两个问题:

  1. 您在for循环期间没有检查键盘输入,因此如果您输入stdin中的随机字符,程序将不会注意到。
  2. 当按下中断键(即Ctrl-C)时,将特别抛出KeyboardInterrupt异常。
  3. 问题是您需要尝试从stdin读取,但不要等到输入出现在那里,如果没有任何开头。 This page提供了如何执行此操作的详细说明。

    根据上面的链接,如果你点击输入,这段代码应该可以使计数停止:

    import sys 
    import select 
    import time
    
    def countup():
        i = 0
        while True:
            print i
            i += 1
            time.sleep(1)
            while sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
                line = sys.stdin.readline()
                if line:
                    r = raw_input("Restart?")
                    if r.lower() == "y":
                        countdown()
                    else:
                        break
    
     countup()