As the title says, I'm writing a Console Menu Generator in Python. I have 2 classes, Menu and Item. But I get into troubles. Here is the code:
class Menu:
def AddItem(self,item):
class Item:
def __init__(self,text,ToDoNext):
self.text=text
??????????????
self.item.append(Item())
def Show():
for i in range(len(self.item)):
print(str(i+1)+") "+str(self.item[i])+"\n")
print("0) Back\n")
option=int(input())
self.item[option].????????????
This code basically do the next:
Main=Menu()
Menu.AddItem("Open file",ToDo1)
Menu.AddItem("Save file",ToDo2)
Menu.Show()
'''1) Open file
2) Save file
0) Back
_
'''
If I write 1 and press enter should do the portion of code ToDo1
, for example.
The solution that I thought is the nextone:
def ToDo1():
print("Hello, world!")
Menu.AddItem("Say Hello","ToDo1()")
and use an eval()
function inside the Show()
.
But I'm not pretty sure this is not the correct way to do that.
I would like you to show me a better way, and if you have ever do something like that (Console Menu Generator) to share the code and see another way of doing the same.
I absolutely recommend creating a class Item
, even if you only have text
and function
attributes!
Who knows what kind of complex logic you will need later on.
With this in mind, creating a menu would probably look something like this:
main = Menu()
main.AddItem(Item("Open", openFile))
main.AddItem(Item("Close", closeFile))
Also, on top of your text
and function
attributes, you should add parent
attribute to the Item
class. parent
simply points at the parent menu of our item:
main = Menu()
# automatically calls main.AddItem(item1)
open = Item("Open", openFile, main)
# automatically sets parent to main
main.Add(Item("Close", closeFile))
Now that we know how a proper Menu
and Item
should work, we can start coding the classes.
Menu
This shouldn't be too hard, all we need are add_item()
, remove_item()
and draw()
methods and a list of items
.
Also it would be good to draw our menu's name, so lets add name
attribute.
class Menu:
def __init__(self, name, items=None):
self.name = name
self.items = items or []
def add_item(self, item):
self.items.append(item)
if item.parent != self:
item.parent = self
def remove_item(self, item):
self.items.remove(item)
if item.parent == self:
item.parent = None
def draw(self):
print(self.label)
for item in self.items:
item.draw()
Obviously we could code much more methods and attributes for our menu, but that includes all the essential methods.
Item
Item class should be even easier, it hardly needs any methods at all.
Item obviously needs a name
and a function
(function will be ran when item gets activated), on top of that it has the earlier mentioned parent
attribute.
We probably should create a setter for parent
, which would automatically move the item under an other menu, but I'll leave that for you if you want to do it.
Also don't forget the draw()
-method for item too, we must be able to draw our items the way they want to be drawn, not the way our Menu
wants to draw them.
class Item:
def __init__(self, name, function, parent=None):
self.name = name
self.function = function
self.parent = parent
if parent:
parent.add_item(self) # use add_item instead of append, since who
# knows what kind of complex code you'll have
# in add_item() later on.
def draw(self):
# might be more complex later, better use a method.
print(" " + self.name)
Final thoughts
We've now finished our menu, it works and you should be able to use it as a basic menu.
However, the superior console menu would only have one class called MenuItem
.
Each item's parent would be an other MenuItem
(each, but the root MenuItem
's of course) and the menu would look something like this when it's drawn:
[-] Root
[+] Submenu of Root
[-] An other submenu of Root
This menu runs functions, others open/close
<This menu has focus on it>
Select this menu by pressing mousedown
[+] A third submenu of Root
Where not giving function
parameter would create items
list and allow users to close/open the menuitem.
If function
is given, it will work normally and only execute the function when selected.
To go even a step further, we would have separated MenuItem
and two subclasses: ActionMenu
and ContainerMenu
.
But please keep in mind, this is somewhat hard to code and not for beginners. You might wanna stick with the first version I went through.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With