Python curses库倒计时器与用户输入功能故障排查求助
修复后的完整代码
import time import threading import curses from threading import Lock def countdown_timer(stdscr, total_seconds, inputs, lock): start_time = time.time() while True: elapsed = time.time() - start_time remaining = max(total_seconds - int(elapsed), 0) # 线程锁保护共享输入变量 with lock: display_text = f"Time Left: {remaining} seconds - Input: {inputs[0]}" stdscr.addstr(0, 0, display_text) stdscr.refresh() if remaining == 0: break # 短间隔休眠,平衡计时精度和CPU占用 time.sleep(0.1) # 倒计时结束提示 with lock: end_text = f"Time's up! - Input: {inputs[0]}" stdscr.addstr(0, 0, end_text) stdscr.refresh() def main(stdscr): # Curses 初始化配置 curses.noecho() curses.cbreak() stdscr.keypad(True) stdscr.nodelay(True) # 设置非阻塞输入,避免线程阻塞 curses.curs_set(1) # 显示光标,明确输入位置 inputs = [""] input_lock = Lock() total_seconds = 45 # 启动计时器线程 timer_thread = threading.Thread( target=countdown_timer, args=(stdscr, total_seconds, inputs, input_lock) ) timer_thread.start() # 主线程专职处理用户输入 while timer_thread.is_alive(): key = stdscr.getch() if key == ord('\n'): break elif key in (curses.KEY_BACKSPACE, 127): # 处理退格键 with input_lock: inputs[0] = inputs[0][:-1] if inputs[0] else "" elif key != -1 and 32 <= key <= 126: # 仅接受可打印字符 with input_lock: inputs[0] += chr(key) # 输入后立即更新显示,实现实时反馈 elapsed = time.time() - start_time remaining = max(total_seconds - int(elapsed), 0) with input_lock: display_text = f"Time Left: {remaining} seconds - Input: {inputs[0]}" stdscr.addstr(0, 0, display_text) stdscr.refresh() time.sleep(0.01) # 降低CPU占用 # 等待计时器线程结束 timer_thread.join() # 等待用户确认退出 stdscr.addstr(1, 0, "Press Enter to exit...") stdscr.nodelay(False) stdscr.getch() if __name__ == "__main__": curses.wrapper(main)
问题根源与修复说明
1. 倒计时跳数/不实时问题
- 原问题:依赖
range循环+time.sleep(1)计时,输入触发的getch()会打断sleep,导致计时周期混乱;两个线程抢用getch(),进一步干扰计时节奏。 - 修复:
- 改用时间戳计算剩余时间,基于启动时间的差值计算剩余时长,不受sleep打断影响。
- 计时器线程用短间隔休眠(0.1秒),既保证每秒更新一次显示,又不会阻塞主线程处理输入。
2. 用户输入无法捕获问题
- 原问题:主线程和计时器线程同时调用
getch(),输入事件被随机抢占;输入后没有实时更新显示,导致输入反馈延迟。 - 修复:
- 让主线程专职处理输入,计时器线程仅负责更新显示,避免资源竞争。
- 添加退格键处理逻辑,支持输入修正;限制仅接受可打印字符,避免控制字符干扰显示。
- 每次输入后立即刷新显示,实现输入内容的实时同步。
3. Curses 初始化/清理问题
- 原问题:手动初始化/清理容易遗漏终端状态恢复;未设置非阻塞输入,导致线程阻塞。
- 修复:
- 使用
curses.wrapper()自动处理Curses的初始化和终端状态恢复,避免异常场景下终端无法正常使用。 - 设置
nodelay(True)让getch()非阻塞,主线程不会因等待输入卡住。 - 显示光标,让用户明确当前输入位置,提升交互体验。
- 用线程锁
Lock()保护共享的输入变量,避免多线程竞争导致的显示异常。
- 使用
内容的提问来源于stack exchange,提问作者edge selcuk
相关产品推荐
相关产品推荐

