This is a simple console menu that just holds a main menu and a few menu "buttons" (numbers and titles which the user has to enter for the button to do its action). It does not need submenus or more complicated input handling.
I went with an object-oriented approach and defined three classes: Menu
, Button
, and Controller
. The Menu
initialises with a name and a list of menu buttons.
class Menu(object):
"""Base class for the menu"""
def __init__(self, name, buttons):
# Initialize values
self.name = name
self.buttons = buttons
def display(self):
"""Displaying the menu alongside the navigation elements"""
# Display menu name
print self.name
# Display menu buttons
for button in self.buttons:
print " ", button.nav, button.name
# Wait for user input
self.userInput()
def userInput(self):
"""Method to check and act upon user's input"""
# This holds the amount of errors for the
# navigation element to input comparison.
errSel = 0
inputSel = raw_input("Enter selection> ")
for button in self.buttons:
# If input equals to button's navigation element
if inputSel == str(button.nav):
# Do the button's function
button.do()
# If input != navigation element
else:
# Increase "error on selection" by one, for
# counting the errors and checking their
# amount against the total number of
# buttons. If greater to or equal that means
# no elements were selected.
# In that case show error and try again
errSel += 1
# No usable input, try again
if errSel >= len(self.buttons):
print "Error on selection; try again."
The Button
class is accepting a name, a function and a navigation element (the number you have to press for it to do the button's action):
class Button(object):
"""Base class for menu buttons"""
def __init__(self, name, func, nav):
# Initialize values
self.name = name
# Function associated with button
self.func = func
# Navigation element; number which user has to enter to do button action
self.nav = nav
def do(self):
# Do the button's function
self.func()
Finally, the Controller. Did I do it the right way? I mean it works but having that while loop cycling with only the raw_input()
function stopping it from spamming infinite messages - is that correct or should I write something that prevents the while loop while a menu was already displayed and is awaiting user input?
class Controller(object):
def __init__(self, menu):
# Initialize values
self.menu = menu
# Start menu displaying / cycling
self.cycle()
def cycle(self):
"""Method for displaying / cycling through the menus"""
while True:
# Display menu and redisplay after button's function completes
# Is this right? Will this loop correctly and never interfere
# with raw_input()?
self.menu.display()
Finally, the code that puts it all together:
import sys
def main():
mainMenuButtonName = Button("Show name", showName, 1)
mainMenuButtonVersion = Button("Show version", showVersion, 2)
mainMenuButtonAbout = Button("Show about", showAbout, 3)
mainMenuButtonQuit = Button("Quit", quit, 0)
mainMenuButtons = [mainMenuButtonName, mainMenuButtonVersion, mainMenuButtonAbout, mainMenuButtonQuit]
mainMenu = Menu("Main menu", mainMenuButtons)
controller = Controller(mainMenu)
controller.cycle()
def showName():
print "My name is..."
def showVersion():
print "My version is 0.1"
def showAbout():
print "I am a demo app for testing menus"
def quit():
sys.exit(0)
if __name__ == "__main__":
main()