我想在程序获取一些特殊的单词时绘制它们,实际上是实时的。 所以我写了这段代码,它做得很好,但我仍然无法使用键盘上的移动键更改指针的位置并从我移动它的位置开始输入。 谁能给我提示怎么做? 这是代码:
from colorama import init
from colorama import Fore
import sys
import msvcrt
special_words = ['test' , 'foo' , 'bar', 'Ham']
my_text = ''
init( autoreset = True)
while True:
c = msvcrt.getch()
if ord(c) == ord('\r'): # newline, stop
break
elif ord(c) == ord('\b') :
sys.stdout.write('\b')
sys.stdout.write(' ')
my_text = my_text[:-1]
#CURSOR_UP_ONE = '\x1b[1A'
#ERASE_LINE = '\x1b[2K'
#print ERASE_LINE,
elif ord(c) == 224 :
set (-1, 1)
else:
my_text += c
sys.stdout.write("\r") # move to the line beginning
for j, word in enumerate(my_text.split()):
if word in special_words:
sys.stdout.write(Fore.GREEN+ word)
else:
sys.stdout.write(Fore.RESET + word)
if j != len(my_text.split())-1:
sys.stdout.write(' ')
else:
for i in range(0, len(my_text) - my_text.rfind(word) - len(word)):
sys.stdout.write(' ')
sys.stdout.flush()
由于您似乎已经在使用
colorama
模块,因此定位光标最简单、最便携的方法应该是使用相应的 ANSI 控制序列(请参阅:http://en.m.wikipedia.org/wiki/ ANSI_转义代码)
您要查找的应该是 CUP – 光标位置 (CSI n ; m H),将光标定位在第 n 行和第 m 列。
代码将如下所示:
def move (y, x):
print("\033[%d;%dH" % (y, x))
即使在不了解上述控制序列的 Windows 控制台中,要让事情正常工作,也是漫长而痛苦的方法,那就是使用 Windows API。
幸运的是,
colorama
模块将为您完成这项(艰苦的)工作,只要您不忘记拨打colorama.init()
。
出于教学目的,我留下了最痛苦的方法的代码,省略了 colorama 模块的功能,一切都手工完成。
import ctypes
from ctypes import c_long, c_wchar_p, c_ulong, c_void_p
#==== GLOBAL VARIABLES ======================
gHandle = ctypes.windll.kernel32.GetStdHandle(c_long(-11))
def move (y, x):
"""Move cursor to position indicated by x and y."""
value = x + (y << 16)
ctypes.windll.kernel32.SetConsoleCursorPosition(gHandle, c_ulong(value))
def addstr (string):
"""Write string"""
ctypes.windll.kernel32.WriteConsoleW(gHandle, c_wchar_p(string), c_ulong(len(string)), c_void_p(), None)
正如评论部分中已经指出的,这种尝试仍然给您留下了问题,您的应用程序只能在指定的控制台中运行,所以也许您仍然想提供一个
curses
版本。
要检测curses是否受支持或者你必须使用Windows API,你可以尝试这样的方法。
#==== IMPORTS =================================================================
try:
import curses
HAVE_CURSES = True
except:
HAVE_CURSES = False
pass
根据 mikyra 和 https://stackoverflow.com/a/10455937/2059351 的答案我已经成功编译了我认为是一个完整的示例for Windows,意思是,您可以将光标移动到某个地方,打印你想要的内容,然后确保光标放回原来的位置。我希望这补充了已接受的答案。
import ctypes
from ctypes import c_ulong, c_void_p, c_wchar_p
def stdout_handle():
return ctypes.windll.kernel32.GetStdHandle(-11)
class _Coord(ctypes.Structure):
_fields_ = [("x", ctypes.c_short), ("y", ctypes.c_short)]
class _SmallRect(ctypes.Structure):
_fields_ = [
("left", ctypes.c_short),
("top", ctypes.c_short),
("right", ctypes.c_short),
("bottom", ctypes.c_short),
]
class _ScreenBufferInfo(ctypes.Structure):
_fields_ = [
("size", _Coord),
("cursor_pos", _Coord),
("attrs", ctypes.c_int),
("window", _SmallRect),
("max_window_size", _Coord),
]
def print_at(text: str, x: int, y: int):
kernel32 = ctypes.windll.kernel32
sbi = _ScreenBufferInfo()
kernel32.GetConsoleScreenBufferInfo(stdout_handle(), ctypes.byref(sbi))
original_position = sbi.cursor_pos
# Adjustment is required as the values are read starting from "1", but we
# need to
x = x - 1
y = y - 1
position = x + (y << 16)
kernel32.SetConsoleCursorPosition(stdout_handle(), position)
kernel32.WriteConsoleW(
stdout_handle(), c_wchar_p(text), c_ulong(len(text)), c_void_p(), None
)
kernel32.SetConsoleCursorPosition(stdout_handle(), original_position)