在控制台界面中断滚动文本的一般方法
General way to interrupt scrolling text in console interface
我正在尝试在控制台中制作游戏并且想要滚动文本。我希望能够按 key/type 输入并跳过滚动并打印其余部分。
到目前为止,我尝试使用 pygame(由于必须激活显示表面而在图片之外),使用 sys.stdin.read(1) 的 asyncio(在 cmd 上阻止了 运行 并且没有查询用户基于异步 ide's).
这是我最近的尝试。
import asyncio,time,sys
global skip
immutablesleep = 0.04
mutablesleep = [immutablesleep]
async def aprintl(string,sep="",end="\n",sleep=mutablesleep):
global skip
for letter in string+end:
print(letter+sep,end="",flush=True)
await asyncio.sleep(sleep[0])
skip = True
async def break_print():
global skip
while not skip:
ch = sys.stdin.read(1)
if len(ch)>0:
mutablesleep[0]=0
skip = True
await asyncio.sleep(0.1)
def printl(*args):
global skip
skip = False
mutablesleep[0] = immutablesleep
asyncio.gather(aprintl(*args),break_print())
在建议模块时请记住我想要 os 系统独立代码,以及在将模块冻结到 exe 时可以轻松连接的东西。
更新:
目前这在中断慢速打印方面功能相当好,但仍然存在两个问题:
1:
按 enter 的中断正在切断打印的行,使其不可读
2:
即使打印完成后线程仍在等待输入。
async def break_print():
global skip, ch
thread = Thread(target=t)
thread.start()
thread.join(timeout=0.1)
while not skip:
if len(ch) > 0:
mutablesleep[0]=0
skip = True
ch = ''
await asyncio.sleep(0.1)
def t():
"""Needed to read from stdin async"""
global ch
ch = sys.stdin.readline()
我相信你的问题与最后一行有关
asyncio.gather(aprintl(*args),break_print())
查看 docs,函数签名如下所示:awaitable asyncio.gather(*aws, loop=None, return_exceptions=False)
。 .gather
调用可能无法按预期工作,因为您没有传递可调用项列表,而是将 aprintl(*args)
传递给 *aws
并且 break_print()
传递给loop
参数
将行更改为下面的行,看看它是否如您所期望的那样工作。
asyncio.gather([aprintl(*args),break_print()])
更新
我让你的代码可以工作,但有一些注意事项
import asyncio
import sys
from threading import Thread
global skip
ch = ''
immutablesleep = 0.04
mutablesleep = [immutablesleep]
async def aprintl(string,sep="",end="\n",sleep=mutablesleep):
global skip
for letter in string+[end]:
if not skip:
print(letter+sep,end="",flush=True)
await asyncio.sleep(sleep[0])
skip = True
async def break_print():
global skip, ch
while not skip:
thread = Thread(target=t)
thread.start()
thread.join(timeout=.1)
if len(ch) > 0:
mutablesleep[0]=0
skip = True
ch = ''
await asyncio.sleep(0.1)
def t():
"""Needed to read from stdin async"""
global ch
ch = sys.stdin.readline()
async def printl(*args):
global skip
skip = False
mutablesleep[0] = immutablesleep
await asyncio.gather(aprintl(*args), break_print())
if __name__ == '__main__':
x = ['asdf ', 'asdf']*5000
asyncio.run(printl(x))
改变了什么
- 添加了
t()
,它在每次 break_print
运行时在线程中运行 0.1 秒——这是必需的,因为我相信您的初始代码不是 运行 的原因是因为它挂在 sys.stdin.read(1)
行
- 运行
printl()
通过 asyncio.run()
- 在
aprintl()
中添加了一个if not skip:
检查,否则它会在跳过后打印整个输入
注意事项
- 您必须按回车键停止打印输出——即使使用
.read()
您必须按回车键。我使用 readline()
因为它会 return 在按下回车键之前输入任何字符(意思是,您可以检查以确保用户在按下回车键之前输入了一些字符:len(ch.strip() > 0): do ...
- 即使在
skip == True
之后脚本也没有退出 -- 这可能是因为 break_print()
在 skip == True
时没有退出,它只会继续循环。
我知道这可能不适用于您的用例,但我希望它至少能给您一些想法。
我正在尝试在控制台中制作游戏并且想要滚动文本。我希望能够按 key/type 输入并跳过滚动并打印其余部分。 到目前为止,我尝试使用 pygame(由于必须激活显示表面而在图片之外),使用 sys.stdin.read(1) 的 asyncio(在 cmd 上阻止了 运行 并且没有查询用户基于异步 ide's).
这是我最近的尝试。
import asyncio,time,sys
global skip
immutablesleep = 0.04
mutablesleep = [immutablesleep]
async def aprintl(string,sep="",end="\n",sleep=mutablesleep):
global skip
for letter in string+end:
print(letter+sep,end="",flush=True)
await asyncio.sleep(sleep[0])
skip = True
async def break_print():
global skip
while not skip:
ch = sys.stdin.read(1)
if len(ch)>0:
mutablesleep[0]=0
skip = True
await asyncio.sleep(0.1)
def printl(*args):
global skip
skip = False
mutablesleep[0] = immutablesleep
asyncio.gather(aprintl(*args),break_print())
在建议模块时请记住我想要 os 系统独立代码,以及在将模块冻结到 exe 时可以轻松连接的东西。
更新:
目前这在中断慢速打印方面功能相当好,但仍然存在两个问题:
1:
按 enter 的中断正在切断打印的行,使其不可读
2:
即使打印完成后线程仍在等待输入。
async def break_print():
global skip, ch
thread = Thread(target=t)
thread.start()
thread.join(timeout=0.1)
while not skip:
if len(ch) > 0:
mutablesleep[0]=0
skip = True
ch = ''
await asyncio.sleep(0.1)
def t():
"""Needed to read from stdin async"""
global ch
ch = sys.stdin.readline()
我相信你的问题与最后一行有关
asyncio.gather(aprintl(*args),break_print())
查看 docs,函数签名如下所示:awaitable asyncio.gather(*aws, loop=None, return_exceptions=False)
。 .gather
调用可能无法按预期工作,因为您没有传递可调用项列表,而是将 aprintl(*args)
传递给 *aws
并且 break_print()
传递给loop
参数
将行更改为下面的行,看看它是否如您所期望的那样工作。
asyncio.gather([aprintl(*args),break_print()])
更新
我让你的代码可以工作,但有一些注意事项
import asyncio
import sys
from threading import Thread
global skip
ch = ''
immutablesleep = 0.04
mutablesleep = [immutablesleep]
async def aprintl(string,sep="",end="\n",sleep=mutablesleep):
global skip
for letter in string+[end]:
if not skip:
print(letter+sep,end="",flush=True)
await asyncio.sleep(sleep[0])
skip = True
async def break_print():
global skip, ch
while not skip:
thread = Thread(target=t)
thread.start()
thread.join(timeout=.1)
if len(ch) > 0:
mutablesleep[0]=0
skip = True
ch = ''
await asyncio.sleep(0.1)
def t():
"""Needed to read from stdin async"""
global ch
ch = sys.stdin.readline()
async def printl(*args):
global skip
skip = False
mutablesleep[0] = immutablesleep
await asyncio.gather(aprintl(*args), break_print())
if __name__ == '__main__':
x = ['asdf ', 'asdf']*5000
asyncio.run(printl(x))
改变了什么
- 添加了
t()
,它在每次break_print
运行时在线程中运行 0.1 秒——这是必需的,因为我相信您的初始代码不是 运行 的原因是因为它挂在sys.stdin.read(1)
行 - 运行
printl()
通过asyncio.run()
- 在
aprintl()
中添加了一个if not skip:
检查,否则它会在跳过后打印整个输入
注意事项
- 您必须按回车键停止打印输出——即使使用
.read()
您必须按回车键。我使用readline()
因为它会 return 在按下回车键之前输入任何字符(意思是,您可以检查以确保用户在按下回车键之前输入了一些字符:len(ch.strip() > 0): do ...
- 即使在
skip == True
之后脚本也没有退出 -- 这可能是因为break_print()
在skip == True
时没有退出,它只会继续循环。
我知道这可能不适用于您的用例,但我希望它至少能给您一些想法。