How to create a menu system for a console, terminal application - python-3.x

I looked for "How to create a menu system for a console, terminal application". None of the proposed Similar questions fully answered my goal.
Add a menu to a console application to manage activities.
Run a selected function.
Clear the output
Display the menu again or exit if done is selected
Therefore, I am approaching this as a Q&A format. It’s OK to Ask and Answer Your Own Questions
Suggested better answers are welcomed.

"""
1. Add a menu to a console application to manage activities.
2. Run a selected function.
3. Clear the output
4. Display the menu again or exit if done is selected
"""
import sys
from os import system
def display_menu(menu):
"""
Display a menu where the key identifies the name of a function.
:param menu: dictionary, key identifies a value which is a function name
:return:
"""
for k, function in menu.items():
print(k, function.__name__)
def one():
print("you have selected menu option one") # Simulate function output.
input("Press Enter to Continue\n")
system('cls') # clears stdout
def two():
print("you have selected menu option two") # Simulate function output.
input("Press Enter to Continue\n")
system('cls') # clears stdout
def three():
print("you have selected menu option three") # Simulate function output.
input("Press Enter to Continue\n")
system('cls') # clears stdout
def done():
system('cls') # clears stdout
print("Goodbye")
sys.exit()
def main():
# Create a menu dictionary where the key is an integer number and the
# value is a function name.
functions_names = [one, two, three, done]
menu_items = dict(enumerate(functions_names, start=1))
while True:
display_menu(menu_items)
selection = int(
input("Please enter your selection number: ")) # Get function key
selected_value = menu_items[selection] # Gets the function name
selected_value() # add parentheses to call the function
if __name__ == "__main__":
main()

I am looking for a similar functionality and found this package: console_menu on PyPI. I haven't tried it out yet but apparently it should be simple to use. I copy their documentation example below.
# Import the necessary packages
from consolemenu import *
from consolemenu.items import *
# Create the menu
menu = ConsoleMenu("Title", "Subtitle")
# Create some items
# MenuItem is the base class for all items, it doesn't do anything when selected
menu_item = MenuItem("Menu Item")
# A FunctionItem runs a Python function when selected
function_item = FunctionItem("Call a Python function", input, ["Enter an input"])
# A CommandItem runs a console command
command_item = CommandItem("Run a console command", "touch hello.txt")
# A SelectionMenu constructs a menu from a list of strings
selection_menu = SelectionMenu(["item1", "item2", "item3"])
# A SubmenuItem lets you add a menu (the selection_menu above, for example)
# as a submenu of another menu
submenu_item = SubmenuItem("Submenu item", selection_menu, menu)
# Once we're done creating them, we just add the items to the menu
menu.append_item(menu_item)
menu.append_item(function_item)
menu.append_item(command_item)
menu.append_item(submenu_item)
# Finally, we call show to show the menu and allow the user to interact
menu.show()

Related

Python 3 Jump Tables

I am trying to figure out how to create a basic jump table, so I can better understand different ways of creating menus in Python 3.5.6. Here is what I have so far:
def command():
selection = input("Please enter your selection: ")
return selection
def one():
print ("you have selected menu option one")
def two():
print ("you have selected menu option two")
def three():
print ("you have selected menu option three")
def runCommand(command):
jumpTable = 0
jumpTable[command]()
jumpTable = {}
jumpTable['1'] = one
jumpTable['2'] = two
jumpTable['3'] = three
def main():
command()
runCommand(command)
if __name__ == "__main__":
main()
As far as I understand, a jump table is simply a way of making a menu selection and calling a specific function associated with that numerical value, taken in by my "command" function. Within the jumpTable, you assign the function to call.
I am getting " File "omitted", line 16, in runCommandjumpTableone
TypeError: 'int' object is not subscriptable
All I want to do is have the user enter a number - 1, 2 or 3 and have that function run. when I get this basic functionality down, I will expand the menu to show the options and be more clear. I just need to get the darn thing to run!
Yes, I am aware of other ways to create menus (IF/ELIF/ELSE) I am just trying to nail this one down!
Thank you in advance!
You are quite close. The only issue is that you are trying to access the command before creating the jumpTable. And I am also not sure why you are setting the variable to 0 first (that's why you get the int is not subscriptible error). So, this is the right order:
def runCommand(command):
jumpTable = {}
jumpTable['1'] = one
jumpTable['2'] = two
jumpTable['3'] = three
jumpTable[command]()
By the way, if you are always creating the same jumpTable, you could create it once, outside the function and simply call jumpTable[command]() in your main function.
Another problem: you should store the value you get from the user and pass that to the next function like this:
cmd = command()
runCommand(cmd)
, or simply pipe the two functions together like this:
runCommand(command())
"""
Based on the original question, the following will.
Add a menu to a console application to manage activities.
Run a selected function.
Clear the output
Display the menu again or exit if done is selected
"""
import sys
from os import system
def display_menu(menu):
"""
Display a menu where the key identifies the name of a function.
:param menu: dictionary, key identifies a value which is a function name
:return:
"""
for k, function in menu.items():
print(k, function.__name__)
def one():
print("you have selected menu option one")
input("Press any Enter to return to menu.")
system('cls') # clears stdout
def two():
print("you have selected menu option two")
input("Press any Enter to return to menu.")
system('cls') # clears stdout
def three():
print("you have selected menu option three")
input("Press any Enter to return to menu.")
system('cls') # clears stdout
def done():
system('cls') # clears stdout
print("Goodbye")
sys.exit()
def main():
# Create a menu dictionary where the key is an integer number and the
# value is a function name.
functions_names = [one, two, three, done]
menu_items = dict(enumerate(functions_names, start=1))
while True:
display_menu(menu_items)
selection = int(
input("Please enter your selection number: ")) # Get function name
selected_value = menu_items[selection] # Gets the function name
selected_value() # add parentheses to call the function
if __name__ == "__main__":
main()

tkinker optionmenu not showing chosen result

import tkinter
window = tkinter.Tk()
def abc(event):
ans=0
numberss=['7','8','9']
omenu2['menu'].delete(0, 'end')
for number in numberss:
omenu2['menu'].add_command(label=numberss[ans], command=efg)
ans=ans+1
def efg(event=None):
print('yee')
numbers = ['1','2', '3']
number=['4','5','6']
var = tkinter.StringVar(window)
var1 = tkinter.StringVar(window)
omenu = tkinter.OptionMenu(window, var, *numbers, command = abc)
omenu.grid(row=1)
omenu2 = tkinter.OptionMenu(window, var1, *number, command = efg)
omenu2.grid(row=2)
after you have entered the first option menu, it will update the second one. when you enter data into the second one, it runs the command, but doesn't show you what you entered. i do not want to include a button, and i know that the command works and not on the second
i found some code that changed the options of the second menu, however when i ran this, the command wouldn't work as it was changed to tkinter.setit (i would also like to know what is does. i do not currently understand it)
omenu2['menu'].add_command(label=numberss[ans], command=tkinter._setit(var1, number))
this has been taken from a larger piece of code, and has thrown the same error
You should set your StringVar(var1) new value.
def abc(event):
numberss=['7','8','9']
omenu2['menu'].delete(0, 'end')
for number in numberss:
omenu2['menu'].add_command(label=number, command=lambda val=number: efg(val))
def efg(val, event=None):
print('yee')
var1.set(val)
You are using for loop so you don't need ans(at least not in this code) since it iterates over items themselves.

Sublime 3 Plugin Storing Quick Panel Return Val

I'm trying to write a simple plugin that generates a quick panel based on some list, waits for the user to select an item, and then performs an action based on the value the user selected. Basically, I'd like to do the following:
class ExampleCommand(sublime_plugin.TextCommand):
def __init__(self):
self._return_val = None
self._list = ['a', 'b', 'c']
def callback(self, idx)
self._return_val = self._list[idx]
def run(self):
sublime.active_window().show_quick_panel(
options, self.callback)
if self._return_val == 'a'
// do something
However, show_quick_panel returns before anything is selected and therefore self._return_val won't be assigned to the index selected until after the if statement runs.
How can I solve this problem? With an event listener? I'm very new to Python and Sublime plugin development.
The show_quick_panel() is asynchronous, so while it is executing the remainder of the run() method is finished executing. The action after selection should be done in the callback. The callback will only be called once the user has either selected an item from the quick panel, or dismisses it.
First, you are using a TextCommand so the signature for the run() method is run(edit, <args>), it requires the edit argument.
Also note that the callback will receive an index of -1 if the user doesn't select anything (dismisses the quick panel) e.g. if the user presses Escape.
Here is the show_quick_panel API:
show_quick_panel(items, on_done, <flags>, <selected_index>, <on_highlighted>)
Shows a quick panel, to select an item in a list. on_done will be called once, with the index of the selected item. If the quick panel was cancelled, on_done will be called with an argument of -1.
items may be a list of strings, or a list of string lists. In the latter case, each entry in the quick panel will show multiple rows.
flags is a bitwise OR of sublime.MONOSPACE_FONT and sublime.KEEP_OPEN_ON_FOCUS_LOST
on_highlighted, if given, will be called every time the highlighted item in the quick panel is changed.
— Sublime Text API Reference
Now, let's rework the example command.
class ExampleCommand(sublime_plugin.TextCommand):
def on_done(self, index):
if index == -1:
# noop; nothing was selected
# e.g. the user pressed escape
return
selected_value = self.items[index]
# do something with value
def run(self, edit):
self.items = ['a', 'b', 'c']
sublime.active_window().show_quick_panel(
self.items,
self.on_done
)
For some more examples on the usage of show_quick_panel() see my polyfill package.
Showing the quickpanel obviously does not block the program execution. I recommend to create and pass a continuation:
import sublime
import sublime_plugin
class ExampleQuickpanelCommand(sublime_plugin.WindowCommand):
def run(self):
# create your items
items = ["a", "b", "c"]
def on_select(index):
if index == -1: # canceled
return
item = items[index]
# process the selected item...
sublime.error_message("You selected '{0}'".format(item))
self.window.show_quick_panel(items, on_select)

tkinter GUI design: managing variables from multiple widgets/toolbars

{Edit: the answer by Bryan Oakley in the suggested duplicate question enter link description here a) fires a response on change to the array variable (arrayvar.trace mode="w"), and I need it triggered on FocusOut, as described in my original question; b) works for Python 2, but I'm having trouble converting it to work in Python 3.5. I'm currently using his and pyfunc's answers as leads and trying to figure out a similar solution using a FocusOut event.}
I am working on a tkinter GUI that lets a user select a particular type of calculation, using a pair of radio button lists. Based on the selections, a tool bar is populated with multiple modular entry widgets, one for each variable the calculation requires. The goal is to have the numerical entry values passed to the model, which will return data to be graphed on a canvas or matplotlib widget.
My question is: what typical strategy is used for gathering and continually refreshing values from multiple widgets, in order to update displays and to pass them on to the model? The trick here is that there will be a large number of possible calculation types, each with their own toolbar. I'd like the active toolbar to be "aware" of its contents, and ping the model on every change to a widget entry.
I think the widgets and the toolbar would have to be classes, where the toolbar can query each widget for a fresh copy of its entry values when a change is detected, and store them as some collection that is passed to the model. I'm not entirely sure how it can track changes to the widgets. Using a "validate='focusout' " validation on the entry widget (e.g. as in
this validation reference )
suggests itself, but I already use "validate='key' " to limit all entries to numbers. I don't want to use "validate=all" and piggyback onto it because I don't want to continually ask the model to do a lengthy calculation on every keypress.
I'm new to GUI programming, however, so I may be barking up the wrong tree. I'm sure there must be a standard design pattern to address this, but I haven't found it.
Below is a screenshot of a mockup to illustrate what I want the GUI to do. The Task radiobutton controls which secondary button menu appears below. The selection in the second menu populates the top toolbar with the necessary entry widgets.
The following code does (mostly) what I want. The ToolBar frame objects will store the values from its contained widgets, and call the appropriate model as needed. The VarBox objects are Entry widgets with extra functionality. Hitting Tab or Return refreshes the data stored in the ToolBar dictionary, tells the ToolBar to send data to the model, and shifts focus to the next VarBox widget.
from tkinter import *
# Actual model would be imported. "Dummy" model for testing below.
def dummy_model(dic):
"""
A "dummy" model for testing the ability for a toolbar to ping the model.
Argument:
-dic: a dictionary whose values are numbers.
Result:
-prints the sum of dic's values.
"""
total = 0
for value in dic.values():
total += value
print('The total of the entries is: ', total)
class ToolBar(Frame):
"""
A frame object that contains entry widgets, a dictionary of
their current contents, and a function to call the appropriate model.
"""
def __init__(self, parent=None, **options):
Frame.__init__(self, parent, **options)
self.vars = {}
def call_model(self):
print('Sending to dummy_model: ', self.vars)
dummy_model(self.vars)
class VarBox(Frame):
"""
A customized Frame containing a numerical entry box
Arguments:
-name: Name of the variable; appears above the entry box
-default: default value in entry
"""
def __init__(self, parent=None, name='', default=0.00, **options):
Frame.__init__(self, parent, relief=RIDGE, borderwidth=1, **options)
Label(self, text=name).pack(side=TOP)
self.widgetName = name # will be key in dictionary
# Entries will be limited to numerical
ent = Entry(self, validate='key') # check for number on keypress
ent.pack(side=TOP, fill=X)
self.value = StringVar()
ent.config(textvariable=self.value)
self.value.set(str(default))
ent.bind('<Return>', lambda event: self.to_dict(event))
ent.bind('<FocusOut>', lambda event: self.to_dict(event))
# check on each keypress if new result will be a number
ent['validatecommand'] = (self.register(self.is_number), '%P')
# sound 'bell' if bad keypress
ent['invalidcommand'] = 'bell'
#staticmethod
def is_number(entry):
"""
tests to see if entry is acceptable (either empty, or able to be
converted to a float.)
"""
if not entry:
return True # Empty string: OK if entire entry deleted
try:
float(entry)
return True
except ValueError:
return False
def to_dict(self, event):
"""
On event: Records widget's status to the container's dictionary of
values, fills the entry with 0.00 if it was empty, tells the container
to send data to the model, and shifts focus to the next entry box (after
Return or Tab).
"""
if not self.value.get(): # if entry left blank,
self.value.set(0.00) # fill it with zero
# Add the widget's status to the container's dictionary
self.master.vars[self.widgetName] = float(self.value.get())
self.master.call_model()
event.widget.tk_focusNext().focus()
root = Tk() # create app window
BarParentFrame = ToolBar(root) # holds individual toolbar frames
BarParentFrame.pack(side=TOP)
BarParentFrame.widgetName = 'BarParentFrame'
# Pad out rest of window for visual effect
SpaceFiller = Canvas(root, width=800, height=600, bg='beige')
SpaceFiller.pack(expand=YES, fill=BOTH)
Label(BarParentFrame, text='placeholder').pack(expand=NO, fill=X)
A = VarBox(BarParentFrame, name='A', default=5.00)
A.pack(side=LEFT)
B = VarBox(BarParentFrame, name='B', default=3.00)
B.pack(side=LEFT)
root.mainloop()

Use return key and a button at the same time in tkinter

I want to write a program for my biology class... I want to integrate the function that you can type something in the Entry bar and then you can use the button or click the return key. I've the problem, that I just can click the button. Everything else don't work. Here is my code (in a simple form):
from tkinter import *
import tkinter as tk
# Main Graphic User Interface
root = Tk()
root.title("Genetic Translator")
root.geometry("300x175")
root.resizable(0,0)
# Solid Label "Information for Input"
s_label2 = Label(root, text = "\nInput Tripplet which decodes for an amino acid:\n")
s_label2.pack()
# Entry Bar
trip = Entry(root)
trip.pack()
# Function for setting focus on entry bar
trip.focus_set()
# Dictionary
output = {"GCX":"Alanine [Ala]"}
# Dict Function Function (Trans: trip -in- AS)
def dict_function1():
global o_screen
o_screen.configure(text=(output.get(trip.get().upper(),"Unknown tripplet!")))
# Bind the Return Key for Input
trip.bind("<Return>", dict_function1)
# Space Label 1
space_label1 = Label(root)
space_label1.pack()
# Button "Confirm"
mainbutton = Button(root, text = "Confirm", command = dict_function1)
mainbutton.pack()
# Space Label 2
space_label2 = Label(root)
space_label2.pack()
# Output Screen
o_screen = Label(root)
o_screen.pack()
# Mainloop function for Interface Options
root.mainloop()
Thank you for helping me.
When you press return key it will send event as argument to dict_function1 and when you click on the button nothing is send.
add argument to dict_function1 with None as default value.
def dict_function1(event=None)
Function assigned to button is called without arguments but assigned by bind is called with argument - event information - so your function have to receive that argument
def dict_function1(event=None): # None for "command="
--
<Return> binded to Entry will work only if Entry is focused, but not when Button is focused. If you bind <Return> to root then <Return> will work in both situations.
You neglected to say what "don't work" means. When I run your code from IDLE, enter 3 letters, and hit return, I get the following
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Programs\Python35\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
TypeError: dict_function1() takes 0 positional arguments but 1 was given
The issue is that when tk calls a 'command', it does not pass any arguments, but when it calls a function bound to an event, it passes an event argument. So add an optional parameter to the function.
def dict_function1(event=None):
It works for me, except for the error message when the Enter key is pressed which you don't provide, so that may or may not be the problem. It is easily fixed, but "everything else don't work" is way too vague to help you with. See "Capturing keyboard events" at http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm You should also include code if the Entry value is not found in the dictionary. Finally, you import Tkinter twice in the first 2 statements in the program. Choose one or the other.
from tkinter import *
# Main Graphic User Interface
root = Tk()
root.title("Genetic Translator")
root.geometry("300x175")
root.resizable(0,0)
# Solid Label "Information for Input"
s_label2 = Label(root, text = "\nInput Tripplet which decodes for an amino acid:\n")
s_label2.pack()
# Entry Bar
trip = Entry(root)
trip.pack()
# Function for setting focus on entry bar
trip.focus_set()
# Dictionary
output = {"GCX":"Alanine [Ala]"}
# Dict Function Function (Trans: trip -in- AS)
def dict_function1(arg=None): ## capture the event from the Return key
##global o_screen
o_screen.configure(text=(output.get(trip.get().upper(),"Unknown tripplet!")))
# Bind the Return Key for Input
trip.bind("<Return>", dict_function1)
# Space Label 1
space_label1 = Label(root)
space_label1.pack()
# Button "Confirm"
mainbutton = Button(root, text = "Confirm", command = dict_function1)
mainbutton.pack()
# Space Label 2
space_label2 = Label(root)
space_label2.pack()
# Output Screen
o_screen = Label(root)
o_screen.pack()
# Mainloop function for Interface Options
root.mainloop()

Resources