在使用python诅咒编程时,我遇到了许多不可预测的行为,我将不在这里讨论。但是现在,在这些问题中有一个特别的问题困扰着我,理解它可能有助于解决其他问题。
只要我不调用stdscr.getkey()。事实上,屏幕每隔半秒就会闪烁一次。如果我调用stdscr。getkey()屏幕闪一次且仅闪一次。按下一个键并进入循环并不会改变任何东西。为什么?我没有找到任何关于flash()和getkey()的文档,可以解释发生了什么。
#! /usr/bin/env python3
import curses
def test(stdscr):
import time
curses.noecho()
curses.cbreak()
curses.curs_set(0)
stdscr.keypad(True)
while True:
curses.flash()
time.sleep(0.5)
# ~ stdscr.getkey()
curses.wrapper(test)
也许一些诅咒功能改变了一些状态,使flash不再工作?但是怎么做,为什么呢?
flash
在curses中使用终端描述中的flash
能力。例如,使用infocmp
,您可能会在输出中看到这样的内容:
flash=E[?5h$<100/>E?5l,
告诉应用程序发送一个转义序列,等待100毫秒,然后发送另一个转义序列。(不是所有的"xter"想要实现DECSCNM
;该缺陷通常在终端数据库注释中注明);
诅咒中的所有屏幕更新都被缓冲;flash
是一个更新。您可以使用refresh
显式地将该缓冲区刷新到终端,或者依赖于读取输入的函数(作为副作用,它将执行refresh
)。如果你的程序被阻止写入终端,你将看不到闪烁。
无论调用getch
还是getkey
,通常都会阻塞直到你按下一个键。您可以使用timeout、nodelay等,这些在文档中有提到。
time.sleep
会干扰刷新。使用napms
. 例如:
> diff -u foo.orig foo
--- foo.orig 2022-07-20 03:53:05.000000000 -0400
+++ foo 2022-07-20 03:56:18.833794715 -0400
@@ -8,10 +8,14 @@
curses.cbreak()
curses.curs_set(0)
stdscr.keypad(True)
-
+ stdscr.nodelay(1)
+
while True:
curses.flash()
- time.sleep(0.5)
- # ~ stdscr.getkey()
-
+ curses.napms(500)
+ try:
+ stdscr.getkey()
+ except curses.error:
+ pass
+
curses.wrapper(test)
进一步阅读:
- Curses Programming with Python
- 哔哔声,闪光-诅咒铃声和屏幕闪光例程
- 读取字符(getch)
OP注释调用use_default_colors有助于flash
。这取决于终端(就像DECSCNM
一样),但它会产生差异的原因是因为python诅咒包装器调用start_color
,这会导致ncurses尝试将终端涂成黑白。调用use_default_colors
在一定程度上取消了这一点,因为脚本中没有使用显式的颜色,因此您将只看到终端的默认颜色。如果终端仿真器仅在使用默认(未着色)配置时显示DECSCNM
,那么这就是您将获得的"工作"。flash .
就护士而言,"flash"与color和refresh的详细信息是分开的(参见源代码)。它只依赖于刷新时完成的缓冲区刷新。
好的,所以它可能不是完美的,但我相信我遇到了一些看起来像一个可能的解决方案。
通过在多个终端模拟器上测试代码片段,如支持透明的终止器,我注意到调用refresh()或getkey()会用新颜色擦除背景。
当它发生时,flash()不再操作。我不确定为什么会发生这种情况(即,为什么refresh(), getch()和getkey()改变颜色设置),但我们在这里。
所以一个工作和可移植的代码(假设visual bell是启用的)看起来像这样:
#! /usr/bin/env python3
import curses
def test(stdscr):
curses.noecho()
curses.cbreak()
curses.curs_set(0)
stdscr.keypad(True)
stdscr.nodelay(1)
curses.use_default_colors()
while True:
curses.flash()
curses.napms(500)
try:
stdscr.getkey()
break
except curses.error:
pass
curses.wrapper(test)
curses.use_default_colors()
欢迎进一步解释!
编辑:查看Thomas Dickey的回答了解更多细节