在Python curses UI中调度函数调用

1 投票
2 回答
2914 浏览
提问于 2025-04-17 13:02

我正在尝试写一个程序,这个程序会有一个curses界面(这样我可以轻松地实时更改设置),同时还能够根据不同的时间安排调用函数并显示输出。

我搞不清楚怎么才能高效地在设定的时间间隔内调用某个东西,同时又能使用一个curses循环,这样就可以随时输入。

下面是一个小程序的例子,试图实现我说的功能。(但没有成功)

import curses, sched, time

from datetime import datetime

def show_time(sc):
    screen.addstr(12, 12, datetime.now())
    sc.enter(1, 1, show_time, (sc,))

screen = curses.initscr()
curses.noecho()
curses.curs_set(0)
screen.keypad(1)

screen.addstr("This is a Sample Curses Script\n\n")

s = sched.scheduler(time.time, time.sleep)
s.enter(1, 1, show_time, (s,))
s.run()
while True:
   event = screen.getch()
   if event == ord("q"): break

curses.endwin()

谢谢!

2 个回答

0

我觉得解决这个问题的最好办法是用GNU readline来处理输入,而不是默认的curses输入。然后利用readline的异步功能,这样你就可以有一个select循环,从中调用函数。

首先,Python的readline库不支持异步的readline函数调用,不过ctypes直接把Python和readline连接起来是很简单的

这样你就有了一个始终在控制中的选择循环。当没有输入时,可以查看时钟,看看是否该运行你的函数。如果还没到时间,就休眠几毫秒,检查一下是否有按键输入,然后再看看时钟,继续休眠。time.sleep可以处理小数秒。

4

你的脚本似乎有两个问题。

  1. 这一行:

    screen.addstr(12, 12, datetime.now())
    

    会引发一个 TypeError 错误,因为 addstr 需要的是一个 str 类型的字符串,而不是 datetime 类型的日期时间。所以你需要把那一行换成类似这样的:

    screen.addstr(12, 12, time.strftime("%a, %d %b %Y %H:%M"))
    
  2. 第二个问题是递归调用的调度:

    sc.enter(1, 1, show_time, (sc,))
    

    我之前没用过调度模块,但我稍微了解了一下,似乎 .run() 方法会一直停下来,直到所有安排的事件都完成。

如果你只是想每秒更新一次屏幕,为什么不试试这样的代码呢:

import curses
import time
import threading

def update_time(screen):
    while 1:
        screen.addstr(12, 12, time.strftime("%a, %d %b %Y %H:%M:%S"))
        screen.refresh()
        time.sleep(1)

screen = curses.initscr()
curses.noecho()
curses.curs_set(0)
screen.keypad(1)

screen.addstr("This is a Sample Curses Script\n\n")
screen.refresh()

clock = threading.Thread(target=update_time, args=(screen,))
clock.daemon = True
clock.start()
while 1:
    event = screen.getch()
    if event == ord("q"):
        break

curses.endwin()

撰写回答