终端菜单 - 向上 - 向下 - 输入 - 使用模块键盘

Menu for terminal - Up - Down - Enter - Using module keyboard

一周前刚开始使用 python。目前我正在尝试编写一个小程序 class,它在终端中创建一个菜单。这个想法是使用向上/向下键浏览菜单。您可以通过按 enter select 菜单项。我使用模块 "keyboard".

控制按下的键

为了使用我的 class,必须创建一个对象并通过方法 "add_menu" 添加菜单项。后面提到的方法有两个参数,第一个用于菜单项的名称,第二个用于传递一个函数,该函数将在按下回车时调用。

为了检查是否按下了某个键,我使用了模块键盘中的方法keyboard.on_press。如果按下某个键,方法 keyboard.on_press 将执行菜单对象的方法 handle_menu。 handle_menu 方法使用名为 "controller" 的列表来组织菜单项的 selection。基本上,它只是一个像 [0,0,1,0] 这样的列表。元素为 1 表示当前 selected 菜单项。

现在解决我的问题:我的菜单有一个菜单项 "Exit"。如果这是 selected 并按下回车键,我希望整个程序停止。因此,如果按下退出,属性 exit 将从 0 更改为 1。在我程序的 while 循环中,我总是检查 object.exit 是否为 != 1,否则程序应该结束。不知何故,这并不总是有效。如果我从一开始就立即向下滚动,而不在其他菜单项上按回车键,它就可以工作。但是,如果我在其他菜单项上多次按回车然后转到退出菜单项,程序不会再结束(或者只有当我按回车 10-20 次时)。感觉keyboard.on_press方法和while循环有时在后台解耦,运行异步?我不太明白这是怎么回事...

import keyboard #Using module keyboard
import os

class bcolors:
    HEADER = '3[95m'
    OKBLUE = '3[94m'
    OKGREEN = '3[92m'
    WARNING = '3[93m'
    FAIL = '3[91m'
    ENDC = '3[0m'
    BOLD = '3[1m'
    UNDERLINE = '3[4m'

def start_function():
    print('Start works')

def save_function():
    print('Save works')

def option_function():
    print('Option works')

class c_menu:

def __init__ (self):
    self.exit = 0
    self.menu = []
    self.functions = []
    self.controller = []

def add_menu(self, menu, function):
    self.menu.append(menu)
    self.functions.append(function)
    if len(self.controller) == 0:
        self.controller.append(1)
    else:
        self.controller.append(0)

def start_menu(self):
    os.system('cls' if os.name == 'nt' else 'clear')
    for menu_item in range(len(self.menu)):
        if self.controller[menu_item] == 1:
            print(bcolors.WARNING + self.menu[menu_item])
        else:
            print(bcolors.OKBLUE + self.menu[menu_item])

def handle_menu(self, event):
    os.system('cls' if os.name == 'nt' else 'clear')
    if event.name == 'down':
        if self.controller.index(1) != (len(self.controller) - 1):
            self.controller.insert(0,0)
            self.controller.pop()
    elif event.name == 'up':
        if self.controller.index(1) != 0:
            self.controller.append(0)
            self.controller.pop(0)
    for menu_item in range(len(self.menu)): #printing all menu items with the right color
        if self.controller[menu_item] == 1:
            print(bcolors.WARNING + self.menu[menu_item])
        else:
            print(bcolors.OKBLUE + self.menu[menu_item])
    if event.name == 'enter':
        if self.functions[self.controller.index(1)] == 'exit':
            self.exit = 1
            return
        self.functions[self.controller.index(1)]()

main_menu = c_menu()

main_menu.add_menu('Start', start_function)
main_menu.add_menu('Save', save_function) 
main_menu.add_menu('Option', option_function)
main_menu.add_menu('Exit', 'exit')

main_menu.start_menu()

keyboard.on_press(main_menu.handle_menu)

while main_menu.exit != 1:
    pass  

我想我理解了这个问题。该程序实际上已正确结束,但是,最后按下的 "enter" 仍在某种缓冲区(或类似的东西)中,并且在程序结束后,终端命令 "python menu.py" 一次又一次地执行(它进行得太快了,看起来程序还没有结束)。不幸的是,我真的不明白为什么会这样。

到目前为止,我的解决方案是在程序的最后(while 循环之后)使用 "keyboard.send('ctrl+c')"。这可以防止终端再次重新执行命令 "python menu.py"。