Python Curses: Returning to the Previous Menu - python

I have a menu system in ncurses.
Choosing one of the options takes you to another menu. But how do I get back?
import curses
def Main():
x = 0
while x!= ord('2'):
x = screen.getch()
screen.clear();screen.border();
screen.addstr(1,1, "Please choose:")
screen.addstr(3,1, "1 - Another Menu")
screen.addstr(4,1, "2 - Exit")
if x==ord('1'):
y = 0
while y!= ord('2'):
y = screen.getch()
screen.clear();screen.border();
screen.addstr(1,1, "Please choose from new menu:")
screen.addstr(3,1, "1 - Do Something new")
screen.addstr(4,1, "2 - Previous Menu")
if y == ord('1'): doSomething()
#Here I exit the internal loop. I need to go back to the previous menu, but I don't know how.
##
##exit outside loop and close program
##
curses.endwin(); exit();
screen = curses.initscr()
Main()
Ideally I'd need to use the GOTO module to jump between lines of code, but the device I'm using does not come with that module built-in.
Do you guys know any other methods? Really appreciate any help.
============ Update: ==================
Okay, I also realized that you can regenerate both menu's with ease:
import curses
def Main():
x = 0
while x!= ord('2'): #draws 1st menu
screen.clear();screen.border();
screen.addstr(1,1, "Please choose:")
screen.addstr(3,1, "1 - Another Menu")
screen.addstr(4,1, "2 - Exit")
x = screen.getch() #grab input AFTER first giving options :)
if x==ord('1'):
y = 0
z = 0
while y!= ord('2'): #draws 2nd menu
screen.clear();screen.border();
screen.addstr(1,1, "Please choose from new menu:")
screen.addstr(3,1, "1 - Do Something new")
screen.addstr(4,1, "2 - Previous Menu")
screen.addstr(6,1, "current loop : "+str(z))
y = screen.getch(); #grabs new input
while z!= -1: #never breaks from loop unless 'break' is called
if y == ord('1'):
z += 1
break #regenerates 2nd menu
break #regenerates 1st menu
#Here we exit the internal loop.
##
##exit outside loop and close program
curses.endwin(); exit();
screen = curses.initscr()
Main()

Add x = 0 after the second while loop ends.
(You need to reset x every time around the loop, not just the first. Otherwise exiting from the first menu will x set to "exit", so will also exit the second menu.)

Related

Python: Change one printed character

I'm making a game with a terminal UI, and the current code is as follows
from ast import Pass
from re import findall
from time import sleep
from ScrFX import invalidOption
from os import system
from getkey import getkey, keys
def main_menu():
hobo = "**********************************************\n" #ho horizontal, bo border
vebo = "** **\n" #ve vertical, bo border
op1 = "** 1) Start Game **\n"
op2 = "** 2) Load Game **\n"
op3 = "** 3) Quit Game **\n"
s = "\n"
mainmenuscreen = (hobo+(vebo*5)+op1+vebo+op2+vebo+op3+vebo+(vebo*5)+hobo)
print(mainmenuscreen)
print("Please choose an option\n")
def userkey():
usse = getkey() #us-er, se-lection
if usse == '1':
print("Start game")
elif usse == '2':
print("load game")
elif usse == '3':
system('cls')
print("Goodbye!")
quit()
elif usse == '0':
print("Secret Menu yay)")
else:
invalidOption()
system('cls')
print(mainmenuscreen)
userkey()
return(usse)
userkey()
main_menu()
Now, I want to be able to have a symbol (let's say ¤) that goes to before the option so something like this:
op1 = "** 1) Start Game **\n"
op2 = "** ¤ 2) Load Game **\n"
op3 = "** 3) Quit Game **\n"
I know I can theoretically bruteforce my way by just changing the printed text values, clearing the screen, and printing it again; but i'm looking for a more elegant way to do it; I remember in BASIC there was a set command to set a specific line in a grid to a specific character, maybe there's something like this in python?
Also, before you say I should use tkinter for GUI; I understand where you come from but learning tkinter is literally like learning to program all over again, having said that I know tkinter is not the best option so I'm open to other libs before starting to commit to one; yet not ready still to commit to one at all.

How to make "menus" without functions or not call them inside eachother?

Im learning python and I already know the basics. So i'm trying to make a simple program: "A note pad".
Im only using the console and I want to have the following menus
main menu, read note menu, write menu, etc. To do that i'm using a function for each menu, printing the menu, using input() to choose the next menu and then I call the function of the next menu.
But if I have a try / except block in a "a menu", and there's an error in another function called inside that block it will go back and execute the except block.
How can might I be able to avoid this, or is there any better way to make the menus?
Here's what I have:
noteList = [["Here goes the title", "Here goes the text", "Here goes the date"], ["Example", "Text Text Text Text Text Text Text Text", "08/08/2020"]] # note list
#-------------Main Menu-------------
def mainMenu():
print(*"NOTES") # title
print("Write:")
print('-The number of the note to read;')
print('-[N] to create a [N]ew note;')
print('-[D] to [D]elete a note;')
print('-[E] to [E]xit;')
# saved notes
if len(noteList) == 0: # no saved notes
print("\nYou have no notes.")
else: # display saved notes
print("\nSaved notes:")
for number in range(len(noteList)):
print(str(number + 1) + "-" + noteList[number][0])
# ask what action to do
action = input()
actionChooser(action)
#-------------Action Chooser-------------
def actionChooser(action):
try:
action = int(action) - 1 # action is int
readNote(action)
except:
if action == "N" or action == "n": # action is N
newNote()
elif action == "D" or action == "d": # action is E
deleteNote()
elif action == "E" or action == "e": # action is S
exit()
else: # invalid action
print("Invalid action.\n")
mainMenu()
#---------------------------------------
def readNote(noteNumber):
print(*"\n" + noteList[noteNumber][0].upper())
print(noteList[noteNumber][1])
mainMenu()
Thanks and my apologies if I have accedently broken one of your rules it's my first post here.
I will describe how I see it in pseudocode:
1. start program
2. defining processing functions
3. print instructions
4. endless loop
5. wait for input
6. action with try/except
7. exit program
And example program:
import sys
def action_howto():
print("""Instructions:
'test' for action_test
'exit' for exit
""")
def action_test():
print("action_test executed\n")
def action_exit():
sys.exit("bye-bye")
def do_action(action):
try:
{
"test": action_test,
"exit": action_exit
}.get(action.lower(), action_howto)()
except Exception as e:
action_howto()
def main():
action_howto()
while True:
action = input()
do_action(action)
if __name__ == "__main__":
main()

Python creating and traversing a simple menu

I am creating my first Python project. What I am working on is a simple text-based metric to standard (and vice versa) conversion program. I am not seeking the code as I want to figure this out myself. However, I am running into a problem traversing the menu. For example, there are 3 menus: main menu, metric menu, and standard menu. The program opens to the main menu. On the main menu the user can choose to navigate to the metric menu, standard menu, or to exit the program. If the user wants to be able to return to the main menu from the metric or standard menus, what would be the best approach? I have tried while loops and if/elif. However, it seems that my code gets really bloated and convoluted. Could someone please give me some advice on creating and traversing text menus in Python?
You can try something like this:
import sys
import os
def switch():
clear = lambda: os.system('cls')
clear()
s = 0
while s != 5:
s = int(input('1)Metric 2)Standard 3)Exit\n'))
if s == 1:
clear = lambda: os.system('cls')
clear()
metric()
elif s == 2:
clear = lambda: os.system('cls')
clear()
standard()
elif s == 3:
clear = lambda: os.system('cls')
clear()
exit()
else:
print('Out of range.')
def metric():
'''Your code here'''
s = int(input('0)Back\n'))
if s == 0:
switch()
else:
print('Out of range.')
def standard():
'''Your code here'''
s = int(input('0)Back\n'))
if s == 0:
switch()
else:
print('Out of range.')
switch()
Since you said you were new to Python, the __init__() method of a class is called when the object is first constructed. You can read the docs on classes here (skip to 9.3).
I don't know how efficient this would be, but you could use a class that stores other objects of the same class:
class Menu:
def __init__(self, content, short_view, submenus = None):
self.content = content
self.short_view = short_view
if submenus != None:
self.choices = dict(enumerate(submenus, 1))
for sub in submenus:
sub.parent = self
else:
self.choices = {}
subsub1 = Menu("this is subsub1 content", "this goes to subsub1")
subsub2 = Menu("this is subsub2 content", "this goes to subsub2")
subsub3 = Menu("this is subsub3 content", "this goes to subsub3")
sub1 = Menu("this is the first sub menu content", "this goes to sub1", [subsub1, subsub2, subsub3])
sub2 = Menu("this is the second sub menu content", "this goes to sub2")
main = Menu("this is the main menu content", "this goes to main, but will never be used", [sub1, sub2])
main.parent = main
current_menu = main
while True:
print(current_menu.content)
print("\n".join([f"[{num}] {current_menu.choices[num].short_view}" for num in current_menu.choices]))
inpt = input("Choice: ")
if inpt == "exit":
break
elif inpt == "back":
current_menu = current_menu.parent
else:
current_menu = current_menu.choices[int(inpt)]
Usage (in shell):
this is the main menu content
[1] this goes to sub1
[2] this goes to sub2
Choice: 1
this is the first sub menu content
[1] this goes to subsub1
[2] this goes to subsub2
[3] this goes to subsub3
Choice: back
this is the main menu content
[1] this goes to sub1
[2] this goes to sub2
Choice: exit
>>>
Try using the following code :
def main():
a=int(input("1) metric\n2) standard\n3) exit\n"))
if a==1:
metric()
elif a==2:
standard()
elif a==3:
main() #return main()
def metric():
# your code
pass
def standard():
# your code
pass
main()

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
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.

python -- Crash when trying to deal with unexpected input

So, I'm just fooling around in python, and I have a little error. The script is supposed to ask for either a 1,2 or 3. My issue is that when the user puts in something other than 1,2 or 3, I get a crash. Like, if the user puts in 4, or ROTFLOLMFAO, it crashes.
EDIT: okay, switched it to int(input()). Still having issues
Here is the code
#IMPORTS
import time
#VARIABLES
current = 1
running = True
string = ""
next = 0
#FUNCTIONS
#MAIN GAME
print("THIS IS A GAME BY LIAM WALTERS. THE NAME OF THIS GAME IS BROTHER")
#while running == True:
if current == 1:
next = 0
time.sleep(0.5)
print("You wake up.")
time.sleep(0.5)
print("")
print("1) Go back to sleep")
print("2) Get out of bed")
print("3) Smash alarm clock")
while next == 0:
next = int(input())
if next == 1:
current = 2
elif next == 2:
current = 3
elif next == 3:
current = 4
else:
print("invalid input")
next = 0
Use raw_input() not input() the latter eval's the input as code.
Also maybe just build a ask function
def ask(question, choices):
print(question)
for k, v in choices.items():
print(str(k)+') '+str(v))
a = None
while a not in choices:
a = raw_input("Choose: ")
return a
untested though
since the input() gives you string value and next is an integer it may be the case that crash happened for you because of that conflict. Try next=int(input()) , i hope it will work for you :)

Categories

Resources