Ad

Menu For Terminal - Up - Down - Enter - Using Module Keyboard

Just started using python one week ago. At the moment I am trying to code a small program class which creates a menu in a terminal. The idea is to go through the menu using up / down keys. You can select a menu item by pressing enter. I control the keys being pressed using the module "keyboard".

In order to use my class, one has to create an object and add menu items by means of the method "add_menu". The latter mentioned method has two arguments, the first one is used for the name of the menu item, the second one is used to hand over a function, which will be called in case enter was pressed.

In order to check if a key was pressed, I use the method keyboard.on_press from the module keyboard. In case a key was pressed, the method keyboard.on_press executes the method handle_menu of the menu object. The handle_menu method uses a list named "controller" in order to organize the selection of a menu item. Basically, it is just a list like [0,0,1,0]. The element being 1 indicates the currently selected menu item.

Now to my problem: My menu has a menu item "Exit". If this is selected and enter is pressed, I want the whole program to stop. Therefore, if exit was pressed the attribute exit is changed from 0 to 1. In the while loop of my program I always check if object.exit is != 1, if not the program should end. Somehow this does not always work. If I scroll down immediately from the beginning, without pressing enter at other menu items, it works. However, if I press enter several times at other menu items and then go to the exit menu item, the program does not end anymore (or only if I press enter for 10-20 times). I have the feeling that the keyboard.on_press method and the while loop are sometimes uncoupled in the background and run asynchronously? I do not really understand what is going on...

import keyboard #Using module keyboard
import os

class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[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  
Ad

Answer

I think I understood the problem. The program is actually ending properly, however, the last "enter" pressed is still in a kind of buffer (or something similar) and after the end of program, the terminal command "python menu.py" is executed again and again (it goes so fast that it looks like the program did not end). Unfortunately, I do not really understand why this is happening.

My solution so far, I use "keyboard.send('ctrl+c')" at the very end of my program (after the while loop). This prevents the terminal to re-execute the command "python menu.py" again.

Ad
source: stackoverflow.com
Ad