How should I write this so I could constantly move between "menus".
#!/bin/env python
import os
class Menu:
def __init__(self):
self.menu = '1'
def Main(self):
os.system('clear')
print "main menu"
test = raw_input()
if test == '2':
self.menu = '2'
def Sub(self):
os.system('clear')
print "sub menu"
test = raw_input()
if test == '1':
self.menu = '1'
menu = Menu()
while menu.menu == '1':
menu.Main()
while menu.menu == '2':
menu.Sub()
At the moment I can swap once. ie I start with menu.Main(), enter '2' and menu.Sub() is shown. But then when I enter '1' the program quits. why does it not go back to showing menu menu.Main() ? Any thoughts welcome!
EDIT:
just needed to put them in a main while loop
The first while loop runs, and when you enter '2', finishes. Therefore, the second while loop will begin to loop.
In the second while loop, you enter '1', which causes the second while loop to finish (because menu.menu is now == '1'). Thus, the program finishes.
Instead, you'll probably want one value for menu (that is neither '1' nor '2') to act as the exit state. For example, 'E'. Then, you can replace your two while loops with the following:
while menu.menu != 'E':
menu.Do()
The "Do" method will handle the menu state if it's 1 or 2.
class Menu:
def __init__(self):
self.menu = '1'
def Do(self):
if self.menu == '1':
self.Main()
elif self.menu == '2':
self.Sub()
def Main(self):
os.system('clear')
print "main menu"
test = raw_input()
if test == '2':
self.menu = '2'
def Sub(self):
os.system('clear')
print "sub menu"
test = raw_input()
if test == '1':
self.menu = '1'
You will still need to make it so that you can actually get to the 'E' case. I'll leave that as a task for you to finish.
First of all, please keep the coding conventions when naming your classes and functions.
modules in python start with lowercase and usually do not include more a than a word, if it does it is separated by underscore. (e.g. datetime)
Classes in python start with uppercase and CamelCased for more than one word. (e.g. MainClass)
functions in python start with lowercase and separated with underscore (e.g. keep_trying)
I have been trying to read your code and misunderstood the code because of your style of naming. It is a bad practise for peer-reviewing, also bad practise for yourself as you will have hard time to understand the other codes.
--
To your question, if you follow the workflow you'll see that when you call menu you cannot call sub as your if statement only checks that if it is 1, not 2.
Here is a better way:
#!/bin/env python
import os
class Menu:
def __init__(self):
self.get_input()
def get_input(self):
input = raw_input()
if input == '1':
self.main()
elif input == '2':
self.sub()
def main(self):
os.system('clear')
print "main menu"
self.get_input()
def sub(self):
os.system('clear')
print "sub menu"
self.get_input()
menu = Menu()
Related
I'm still super beginner in learning python right now and english is not my native language .I hope there is someone can answer my problem. My concern is how can I end all the loop when enter 'e'. I try to modify the code so that it exit all the loop when enter 'e' but the when I also enter 'm' , it also same when enter 'e' instead I want to return back to the menu loop when I enter 'm'. Thank you. Code below
def A():
print("a")
def B():
print("B")
def Menu():
print("Menu")
print("1.A")
print("2.B")
while True:
Menu()
while True:
option = input("Choose a or b")
if option == 'a':
A()
break
elif option == 'b':
B()
break
else:
print("Choose 'a' or 'b' only")
while True:
repeat = input("'m' or 'e'")
if repeat != 'e' and repeat != 'm':
print("Choose 'm' or 'e' only'")
if repeat == 'm':
break
if repeat == 'e':
break
break
I undestand your problem so I'll give you the only clean solution:
while True: # A loop
while True: # B loop
...
# Now from here...
# ...you want to go here?
If you want to exit both B and A loop from inside B loop, there's only one clean way:
def foo():
while True:
while True:
...
return # Will end both loops
Put the whole thing into a function and replace the "double break" with return.
There's an other solution that I would nickname "boolean label solution" which works in most cases but it's less clean so I will just give you a clue.
flag = true
while flag:
while True:
if (condition_to_exit):
flag = false
break
If you just wish to exit the program after exiting the loops, just use the exit() function:
while True:
...
while True:
...
exit()
I'd recommend creating functions for the user input, this way your code will be cleaner and easier to understand.
Look how clean the main loop looks now, it's very clear what it does:
Executes the Menu function
Lets the user choose whether to execute A or B
Asks user to input "m" or "e"
If user inputs "e" it breaks the loop
That's the steps the main loop has to do, so that's all the code that should be there. Code for checking if the user inputs the right options is not the main loop business, it should be inside a function.
This way you delegate tasks and responsibilities to different parts of the code, which for bigger projects it might not be you who programs them.
The code than be further improved and refactored, for example you might want to use dictionaries for the options of your menu. So each key is an option and the value is the function to be executed. This way your Menu() would be just a loop iterating over the dictionary to display the options and then executing the associated function.
Also you might want to take a look at classes, since all this will fit better encapsulated inside a class.
But first and most important: Keep your code clean, self descriptive and organized.
def A():
print("a")
def B():
print("B")
def Menu():
print("Menu")
print("1.A")
print("2.B")
def ExecuteAorB():
while True:
option = input("Choose a or b")
if option == 'a':
A()
break
elif option == 'b':
B()
break
else:
print("Choose 'a' or 'b' only")
def AskUserMorE():
while True:
repeat = input("'m' or 'e'")
if repeat not in ('e', 'm'):
print("Choose 'm' or 'e' only'")
else:
return repeat
while True:
Menu()
ExecuteAorB()
userInput = AskUserMorE()
if userInput == 'e':
break
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()
Im trying to create a menu. The idea is to make the script loop back to the main menu when the number two is selected. It loops back but when i select number 1 it just keeps looping. How do i fix this.
import os
import sys
def mainmenu():
print """
this is a test menu
"""
mainmenu()
choice = raw_input("DMF>>")
if choice == '1':
def men1():
print """
this is the second menu
"""
men1()
def back():
men1_actions['mainmenu']()
men1_actions = {
'mainmenu': mainmenu,
'2': back,
}
while True:
choice2 = raw_input("DMF>>")
if choice2 == '2':
back()
I'm not sure with what you are pertaining to exactly but you can first define the functions and then just call on one raw_input to indicate whether the input is 1 or 2.
def mainmenu():
print """this is a test menu"""
def men1():
print """this is the second menu"""
while True:
choice = raw_input("DMF>>")
if choice == '1':
mainmenu()
elif choice == '2':
men1()
else:
print """Please choose between 1 or 2"""
I am new to python and learning quickly. Thank you all for the help.
I am attempting to create a text menu that will always run in the background of a storytelling text rpg. I have searched and cannot find an explanation of how to create an "always on" menu or how one would work.
I would like the player to be able to hit "m" at any time in the game and have the menu prompt show up.
So far, I have created a "userinput" function as well as a "menu" function that will be deployed each time the game prompts the user/player for input.
def menu():
print('Press "1" for map >>> "2" for stats >>> "3" for exit')
choice = input()
if choice == '1':
print('map needs to be made and shown')
elif choice == '2':
print('stats need to be made and assinged to choice 2 in def menu')
elif choice == '3':
print('You are exiting the menu. Press "M" at any time to return to the menu')
return
else:
print('I did not recognize your command')
menu()
def userinput():
print('Press 1 to attack an enemy >>> 2 to search a room >>> 3 to exit game')
print('Press "M" for menu at any time')
inputvalue = input()
if inputvalue == 'm':
menu()
elif inputvalue == '1':
print('attack function here')
elif inputvalue == '2':
print('search function here')
elif inputvalue == '3':
exit
else:
userinput()
This does not appear to be an ideal solution because the user cannot choose to view a map or exit the game at any time they want.
Is there a way to have a menu always running in the background?
I thought of using a while loop that would never close and all of the game would be held within that while loop but that doesn't seem economical by any means.
Any thoughts or help would be appreciated.
I took a stab at it. This is perhaps not the best structure for doing what you're looking for but I don't want my reply to get too complicated.
The "standard" approach for anything with a UI is to separate the model, the view and the control. Check out MVC architecture online. While it adds complexity at the start it makes life much simpler in the long run for anything with a non trivial UI.
Other points of note are:
you're not stripping whitespace from your input (potentially problematic "3 " won't do what you want)
you're input is case sensitive (you ask for "M" but check for "m") .. maybe use choice = choice.strip.lower()??
there's a difference between the way raw_input and input work between Python 2 and Python 3 which means your code doesn't work in python 2. What's the difference between raw_input() and input() in python3.x? I've changed my example to use raw_input. You may want to use this work around http://code.activestate.com/recipes/577836-raw_input-for-all-versions-of-python/ near the top of your code for portability.
Some code
# flag we set when we're done
finished = False
def finish():
# ask the user for confirmation?
global finished
finished = True
return
def handle_menu_input(choice):
handled = True
if choice == '1':
print('map needs to be made and shown')
elif choice == '2':
print('stats need to be made and assinged to choice 2 in def menu')
else:
handled = False
return handled
def menu():
finished_menu = False
while not finished_menu:
print('Press "1" for map >>> "2" for stats >>> "3" for exit')
choice = raw_input() # NOTE: changes behaviour in Python 3!
if handle_menu_input(choice):
# done
pass
elif choice == '3':
print('You are exiting the menu. Press "M" at any time to return to the menu')
finished_menu = True
else:
print('I did not recognize your command')
menu()
return
def userinput():
print('Press 1 to attack an enemy >>> 2 to search a room >>> 3 to exit game')
print('Press "M" for menu at any time')
choice = raw_input() # NOTE: changes behaviour in Python 3!
if choice == 'm':
menu()
elif choice == '1':
print('attack function here')
elif choice == '2':
print('search function here')
elif choice == '3':
finish()
# elif handle_menu_input(choice):
# # delegate menu functions?? ..
# # do this if you want to see maps anytime without going through the menu?
# # otherwise comment this elif block out.
# # (Problem is 1, 2 etc are overloaded)
# pass
else:
print('I did not recognize your command')
return
def main():
# main loop
while not finished:
userinput()
return
if __name__ == "__main__":
main()
I am trying to create menu where user can choose which part of the program he/she wants to run. When I am importing function computer automatically runs it rather to wait for user input. What shall I do to run function only when called? My code:
import hangman
menu = raw_input("""Welcome to Menu, please choose from the following options:
1. Hangman game
2.
3.
4. Exit
""")
if menu == 1:
hangman()
elif menu == 2:
"Something"
elif menu == 3:
"Something"
elif menu == 4:
print "Goodbye"
else:
print "Sorry, invalid input"
The code for hangman.py looks like that:
import random
words = ["monitor", "mouse", "cpu", "keyboard", "printer",]
attempts = [] # Stores user input
randomWord = random.choice(words) # Computer randomly chooses the word
noChar = len(randomWord) # Reads number of characters in the word
print randomWord , noChar
print "Hello, Welcome to the game of Hangman. You have to guess the given word. The first word has", noChar, " letters."
def game():
guess = raw_input ("Please choose letter")
attempts.append(guess) # Adds user input to the list
print (attempts)
if guess in randomWord:
print "You have guessed the letter"
else:
print "Please try again"
while True:
game()
chance = raw_input ("Have a guess")
if chance == randomWord:
print "Congratulations, you have won!"
break
Without seeing hangman.py, I would assume that it directly contains the code for running the hangman game, not wrapped in a function. If that's the case, you created a module, no function (yet).
Wrap that code in
def run_hangman():
# Your existing code, indented by 4 spaces
# ...
import it like this:
from hangman import run_hangman
and finally call the function like this:
run_hangman()
So here is the start menu:
import hangman
option = raw_input('1) Start Normal\n2) Quick Start\n3) Default') # '\n' is a new line
if option == '1':
hangman.main()
elif option == '2':
hangman.run_hangman('SKIP')
elif option == '3':
handman.run_hangman('Default User')
Inside your hangman code you want to have it modulated. You should have somthing like this:
def main():
stuff = raw_input('Starting new game. Please enter stuff to do things')
run_hangman(stuff)
def run_hangman(options):
if options == 'SKIP':
important_values = 5
vales_set_by_user = 'Player 1'
else:
values_set_by_user = options
rest_of_code()