Python curses 不接受 curses.KEY_UP 作为输入
Python curses not accept curses.KEY_UP as input
我需要你的帮助来理解我基于菜单的新 python 程序中的错误。
我使用 curses 库创建了一个基于 python 的菜单。当通过 getch()
获取用户输入时,该程序通过接受包括特殊键在内的所有键作为输入来与主菜单选项一起正常工作,但是对于子菜单列表,它无法接受特殊键作为输入。
# Increment or Decrement
elif c == curses.KEY_DOWN: # down arrow
if self.option < len(self.submenu):
self.option += 1
else: self.option = 0
elif c == curses.KEY_UP: # up arrow
if self.option > 0:
self.option -= 1
else: self.option = len(self.submenu)
因此,在上述条件下,我正在使用 select 选项,但当我使用 UP/DOWN 箭头键时,没有输入被发送到 curses
我在下面分享我的完整代码
import curses, os, traceback, json
file1 = json.loads(open('/etc/ansible/org/json/tag_definition.json').read())
submenu = list(file1.keys())
cfg_dict = {'InstanceName': 'NONE',
'Environment': 'NONE',
'InstanceType':'t2.micro',
'SystemOwner':'1',
'LifeCycle':'NONE',
'DeptName':'NONE',
'Org':'NONE'}
class CursedMenu(object):
'''A class which abstracts the horrors of building a curses-based menu system'''
def __init__(self):
'''Initialization'''
self.screen = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
self.screen.keypad(1)
# Highlighted and Normal line definitions
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
self.highlighted = curses.color_pair(1)
self.normal = curses.A_NORMAL
def show(self, options, title="Title", subtitle="Subtitle"):
'''Draws a menu with the given parameters'''
self.set_options(options)
self.title = title.upper()
self.subtitle = subtitle.upper()
self.selected = 0
self.draw_menu()
def set_options(self, options):
'''Validates that the last option is "Exit"'''
if options[-1] is not 'Exit':
options.append('Exit')
self.options = options
def set_submenu(self, submenu):
'''Validates that the last option is "Exit"'''
if submenu[-1] is not 'Exit':
submenu.append('Exit')
self.submenu = submenu
def draw_dict(self):
self.screen.addstr(8, 35, " "*43, curses.A_BOLD)
self.screen.addstr(10, 35," "*43, curses.A_BOLD)
self.screen.addstr(12, 35," "*43, curses.A_BOLD)
self.screen.addstr(14, 35," "*43, curses.A_BOLD)
self.screen.addstr(16, 35," "*43, curses.A_BOLD)
self.screen.addstr(18, 35," "*43, curses.A_BOLD)
self.screen.addstr(20, 35," "*43, curses.A_BOLD)
self.screen.addstr(8, 35, cfg_dict['InstanceName'], curses.A_STANDOUT)
self.screen.addstr(10, 35,cfg_dict['Environment'], curses.A_STANDOUT)
self.screen.addstr(12, 35,cfg_dict['InstanceType'], curses.A_STANDOUT)
self.screen.addstr(14, 35,cfg_dict['SystemOwner'], curses.A_STANDOUT)
self.screen.addstr(16, 35,cfg_dict['LifeCycle'], curses.A_STANDOUT)
self.screen.addstr(18, 35,cfg_dict['DeptName'], curses.A_STANDOUT)
self.screen.addstr(20, 35,cfg_dict['Org'], curses.A_STANDOUT)
self.screen.refresh()
def draw_menu(self):
'''Actually draws the menu and handles branching'''
request = ""
try:
while request is not "Exit":
self.draw()
request = self.get_user_input()
self.handle_request(request)
self.__exit__()
# Also calls __exit__, but adds traceback after
except Exception as exception:
self.__exit__()
traceback.print_exc()
def draw(self):
'''Draw the menu and lines'''
#self.screen.border(0)
self.screen.subwin(40, 80, 0, 0).box()
self.screen.addstr(2,30, self.title, curses.A_STANDOUT|curses.A_BOLD) # Title for this menu
self.screen.hline(3, 1, curses.ACS_HLINE, 78)
self.screen.addstr(4,2, self.subtitle, curses.A_BOLD) #Subtitle for this menu
# Display all the menu items, showing the 'pos' item highlighted
left = 2
for index in range(len(self.options)):
menu_name = len(self.options[index])
textstyle = self.normal
if index == self.selected:
textstyle = self.highlighted
self.screen.addstr(5, left, "%d.%s" % (index+1, self.options[index]), textstyle)
left = left + menu_name + 3
self.screen.addstr(8, 4, " Instance Name:", curses.A_BOLD)
self.screen.addstr(10, 4," Environment:", curses.A_BOLD)
self.screen.addstr(12, 4," Instance Type:", curses.A_BOLD)
self.screen.addstr(14, 4," SystemOwner:", curses.A_BOLD)
self.screen.addstr(16, 4," LifeCycle:", curses.A_BOLD)
self.screen.addstr(18, 4," Department Name:", curses.A_BOLD)
self.screen.addstr(20, 4," Org:", curses.A_BOLD)
self.draw_dict()
self.screen.refresh()
def get_user_input(self):
'''Gets the user's input and acts appropriately'''
user_in = self.screen.getch() # Gets user input
'''Enter and Exit Keys are special cases'''
if user_in == 10:
return self.options[self.selected]
if user_in == 27:
return self.options[-1]
if user_in == (curses.KEY_END, ord('!')):
return self.options[-1]
# This is a number; check to see if we can set it
if user_in >= ord('1') and user_in <= ord(str(min(9,len(self.options)+1))):
self.selected = user_in - ord('0') - 1 # convert keypress back to a number, then subtract 1 to get index
return
# Increment or Decrement
if user_in == curses.KEY_LEFT: # left arrow
self.selected -=1
if user_in == curses.KEY_RIGHT: # right arrow
self.selected +=1
self.selected = self.selected % len(self.options)
return
def handle_request(self, request):
'''This is where you do things with the request'''
if request is "Org":
self.org_func()
if request is None: return
def org_func(self):
'''Actually draws the submenu and handles branching'''
c = None
self.option = 0
self.set_submenu(submenu)
height = len(self.submenu)
while c != 10:
self.s = curses.newwin(height+2, 20, 6, 14)
self.s.box()
for index in range(len(self.submenu)):
textstyle = self.normal
if index == self.option:
textstyle = self.highlighted
self.s.addstr(index+1,1, "%d-%s" % (index+1, self.submenu[index]), textstyle)
self.s.refresh()
c = self.s.getch() # Gets user input
if c == ord('k'):
d = self.submenu[self.option]
cfg_dict['Org'] = file1[d]['Org']
# This is a number; check to see if we can set it
if c >= ord('1') and c <= ord(str(len(self.submenu)+1)):
self.option = c - ord('0') - 1 # convert keypress back to a number, then subtract 1 to get index
# Increment or Decrement
elif c == curses.KEY_DOWN: # down arrow
if self.option < len(self.submenu):
self.option += 1
else: self.option = 0
elif c == curses.KEY_UP: # up arrow
if self.option > 0:
self.option -= 1
else: self.option = len(self.submenu)
return self.option
def __exit__(self):
curses.endwin()
os.system('clear')
'''demo'''
cm = CursedMenu()
cm.show(['Instance-ID','Org','Tag'], title='Instance Launch', subtitle='Options')
如果我使用字母和数字作为输入但不使用特殊键,它工作得很好。我使用了下面的代码并且它正在运行
elif c == ord('k'): # down arrow
if self.option < len(self.submenu):
self.option += 1
else: self.option = 0
elif c == ord('i'): # up arrow
if self.option > 0:
self.option -= 1
else: self.option = len(self.submenu)
请帮助理解为什么代码不接受特殊密钥。
下面是我用过的输入法json
{
"Dept1": {
"Instance Name": "instance1",
"Environment": "environment1",
"SystemOwner": "Owner1",
"LifeCycle": "Lcy1",
"DeptName": "Check1",
"Org": "CSO"
}
}
当你
self.s = curses.newwin(height+2, 20, 6, 14)
您省略了新 window 的设置属性,例如
self.s.keypad(1)
我需要你的帮助来理解我基于菜单的新 python 程序中的错误。
我使用 curses 库创建了一个基于 python 的菜单。当通过 getch()
获取用户输入时,该程序通过接受包括特殊键在内的所有键作为输入来与主菜单选项一起正常工作,但是对于子菜单列表,它无法接受特殊键作为输入。
# Increment or Decrement
elif c == curses.KEY_DOWN: # down arrow
if self.option < len(self.submenu):
self.option += 1
else: self.option = 0
elif c == curses.KEY_UP: # up arrow
if self.option > 0:
self.option -= 1
else: self.option = len(self.submenu)
因此,在上述条件下,我正在使用 select 选项,但当我使用 UP/DOWN 箭头键时,没有输入被发送到 curses
我在下面分享我的完整代码
import curses, os, traceback, json
file1 = json.loads(open('/etc/ansible/org/json/tag_definition.json').read())
submenu = list(file1.keys())
cfg_dict = {'InstanceName': 'NONE',
'Environment': 'NONE',
'InstanceType':'t2.micro',
'SystemOwner':'1',
'LifeCycle':'NONE',
'DeptName':'NONE',
'Org':'NONE'}
class CursedMenu(object):
'''A class which abstracts the horrors of building a curses-based menu system'''
def __init__(self):
'''Initialization'''
self.screen = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
self.screen.keypad(1)
# Highlighted and Normal line definitions
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
self.highlighted = curses.color_pair(1)
self.normal = curses.A_NORMAL
def show(self, options, title="Title", subtitle="Subtitle"):
'''Draws a menu with the given parameters'''
self.set_options(options)
self.title = title.upper()
self.subtitle = subtitle.upper()
self.selected = 0
self.draw_menu()
def set_options(self, options):
'''Validates that the last option is "Exit"'''
if options[-1] is not 'Exit':
options.append('Exit')
self.options = options
def set_submenu(self, submenu):
'''Validates that the last option is "Exit"'''
if submenu[-1] is not 'Exit':
submenu.append('Exit')
self.submenu = submenu
def draw_dict(self):
self.screen.addstr(8, 35, " "*43, curses.A_BOLD)
self.screen.addstr(10, 35," "*43, curses.A_BOLD)
self.screen.addstr(12, 35," "*43, curses.A_BOLD)
self.screen.addstr(14, 35," "*43, curses.A_BOLD)
self.screen.addstr(16, 35," "*43, curses.A_BOLD)
self.screen.addstr(18, 35," "*43, curses.A_BOLD)
self.screen.addstr(20, 35," "*43, curses.A_BOLD)
self.screen.addstr(8, 35, cfg_dict['InstanceName'], curses.A_STANDOUT)
self.screen.addstr(10, 35,cfg_dict['Environment'], curses.A_STANDOUT)
self.screen.addstr(12, 35,cfg_dict['InstanceType'], curses.A_STANDOUT)
self.screen.addstr(14, 35,cfg_dict['SystemOwner'], curses.A_STANDOUT)
self.screen.addstr(16, 35,cfg_dict['LifeCycle'], curses.A_STANDOUT)
self.screen.addstr(18, 35,cfg_dict['DeptName'], curses.A_STANDOUT)
self.screen.addstr(20, 35,cfg_dict['Org'], curses.A_STANDOUT)
self.screen.refresh()
def draw_menu(self):
'''Actually draws the menu and handles branching'''
request = ""
try:
while request is not "Exit":
self.draw()
request = self.get_user_input()
self.handle_request(request)
self.__exit__()
# Also calls __exit__, but adds traceback after
except Exception as exception:
self.__exit__()
traceback.print_exc()
def draw(self):
'''Draw the menu and lines'''
#self.screen.border(0)
self.screen.subwin(40, 80, 0, 0).box()
self.screen.addstr(2,30, self.title, curses.A_STANDOUT|curses.A_BOLD) # Title for this menu
self.screen.hline(3, 1, curses.ACS_HLINE, 78)
self.screen.addstr(4,2, self.subtitle, curses.A_BOLD) #Subtitle for this menu
# Display all the menu items, showing the 'pos' item highlighted
left = 2
for index in range(len(self.options)):
menu_name = len(self.options[index])
textstyle = self.normal
if index == self.selected:
textstyle = self.highlighted
self.screen.addstr(5, left, "%d.%s" % (index+1, self.options[index]), textstyle)
left = left + menu_name + 3
self.screen.addstr(8, 4, " Instance Name:", curses.A_BOLD)
self.screen.addstr(10, 4," Environment:", curses.A_BOLD)
self.screen.addstr(12, 4," Instance Type:", curses.A_BOLD)
self.screen.addstr(14, 4," SystemOwner:", curses.A_BOLD)
self.screen.addstr(16, 4," LifeCycle:", curses.A_BOLD)
self.screen.addstr(18, 4," Department Name:", curses.A_BOLD)
self.screen.addstr(20, 4," Org:", curses.A_BOLD)
self.draw_dict()
self.screen.refresh()
def get_user_input(self):
'''Gets the user's input and acts appropriately'''
user_in = self.screen.getch() # Gets user input
'''Enter and Exit Keys are special cases'''
if user_in == 10:
return self.options[self.selected]
if user_in == 27:
return self.options[-1]
if user_in == (curses.KEY_END, ord('!')):
return self.options[-1]
# This is a number; check to see if we can set it
if user_in >= ord('1') and user_in <= ord(str(min(9,len(self.options)+1))):
self.selected = user_in - ord('0') - 1 # convert keypress back to a number, then subtract 1 to get index
return
# Increment or Decrement
if user_in == curses.KEY_LEFT: # left arrow
self.selected -=1
if user_in == curses.KEY_RIGHT: # right arrow
self.selected +=1
self.selected = self.selected % len(self.options)
return
def handle_request(self, request):
'''This is where you do things with the request'''
if request is "Org":
self.org_func()
if request is None: return
def org_func(self):
'''Actually draws the submenu and handles branching'''
c = None
self.option = 0
self.set_submenu(submenu)
height = len(self.submenu)
while c != 10:
self.s = curses.newwin(height+2, 20, 6, 14)
self.s.box()
for index in range(len(self.submenu)):
textstyle = self.normal
if index == self.option:
textstyle = self.highlighted
self.s.addstr(index+1,1, "%d-%s" % (index+1, self.submenu[index]), textstyle)
self.s.refresh()
c = self.s.getch() # Gets user input
if c == ord('k'):
d = self.submenu[self.option]
cfg_dict['Org'] = file1[d]['Org']
# This is a number; check to see if we can set it
if c >= ord('1') and c <= ord(str(len(self.submenu)+1)):
self.option = c - ord('0') - 1 # convert keypress back to a number, then subtract 1 to get index
# Increment or Decrement
elif c == curses.KEY_DOWN: # down arrow
if self.option < len(self.submenu):
self.option += 1
else: self.option = 0
elif c == curses.KEY_UP: # up arrow
if self.option > 0:
self.option -= 1
else: self.option = len(self.submenu)
return self.option
def __exit__(self):
curses.endwin()
os.system('clear')
'''demo'''
cm = CursedMenu()
cm.show(['Instance-ID','Org','Tag'], title='Instance Launch', subtitle='Options')
如果我使用字母和数字作为输入但不使用特殊键,它工作得很好。我使用了下面的代码并且它正在运行
elif c == ord('k'): # down arrow
if self.option < len(self.submenu):
self.option += 1
else: self.option = 0
elif c == ord('i'): # up arrow
if self.option > 0:
self.option -= 1
else: self.option = len(self.submenu)
请帮助理解为什么代码不接受特殊密钥。
下面是我用过的输入法json
{
"Dept1": {
"Instance Name": "instance1",
"Environment": "environment1",
"SystemOwner": "Owner1",
"LifeCycle": "Lcy1",
"DeptName": "Check1",
"Org": "CSO"
}
}
当你
self.s = curses.newwin(height+2, 20, 6, 14)
您省略了新 window 的设置属性,例如
self.s.keypad(1)