Python Forum
Easygui [HELP] - How could I convert my enterbox into a multenterbox in python?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Easygui [HELP] - How could I convert my enterbox into a multenterbox in python?
#1
Hello, so I want to make all four abilities: "Strength", "Speed", "Stealth", "Cunning" to be placed in one window -- since right now with the enterbox, I have to press "OK" to move onto the next ability, after I've inputted the value for it, four times until it is added to the nested dictionary (card_catalogue). I have attempted to manipulate the code from enterbox to multenterbox for a few hours, just cannot get it to work. This is probably very simple to do, if anybody could help that would be sincerely appreciated.

Here is the original code.

def add_items(combo): 

    '''Allows the user to add items to a specified combo.''' 

    msg = "Enter item/s for combo, separated by a comma." 

    title  = "Enter card items" 

    items = easygui.enterbox(msg, title) 

 
    items_list = items.split(",") 

    

    for i in items_list: 

        # Input handling: To handle a situation where the user enters 

        # a space after the comma when entering items. 

        item = i.strip() 

        msg = item + ": Enter Strength/Speed/Stealth/Cunning Value:" 

        title  = item + " Monster Card Value:" 

        card_catalogue[combo][item] = easygui.enterbox(msg, title) 

 

    # Calls function to display combo. 

    show_menu(combo) 
Finally, here is the attempt I have made to convert it to a multenterbox, which does not add to the dictionary like this - "Strength: 5", and the other 3 abilities, instead it displays "['1', '2', '3', '4']" (For the input values of the abilities (strength, speed, stealth, cunning):

def add_items(combo): 

    '''Allows the user to add items to a specified combo.''' 

    msg = "Enter item/s for combo, separated by a comma." 

    title  = "Enter card items" 

    items = easygui.enterbox(msg, title) 

 
    items_list = items.split(",") 

    

    for i in items_list: 

        # Input handling: To handle a situation where the user enters 

        # a space after the comma when entering items. 

        item = i.strip() 

        msg = item + ": Enter Value" 

        title  = item + " Monster Card Value:" 

        values = "Strength","Speed","Stealth","Cunning" 

        card_catalogue[combo][item] = easygui.multenterbox(msg, title, values) 

 

    # Calls function to display combo. 

    show_menu(combo) 
This is what I am wanting from the input taken from the multenterbox:

Strength: 5
Speed: 15
Stealth: 4
Cunning: 21

Let me know if anything else should be provided! :-)
Reply
#2
I followed the example provided for multienterbox here:

https://easygui.readthedocs.io/en/latest...l#enterbox

And came up with this:
import easygui as gui

def get_fields(fields, title="Statistics", prompt="Enter Statistics"):
    values = gui.multenterbox(prompt, title, fields)

    # make sure that none of the fields were left blank
    while True:
        message = None

        missing_fields = ", ".join([field for field, value in zip(fields, values) if not value.strip()])
        if missing_fields:
            message = f"Enter values for {missing_fields}"
        else:
            try:
                values = list(map(int, values))
            except ValueError:
                message = "Entries must be integers"

        if message:
            values = gui.multenterbox(message, title, fields, values)
        else:
            return {field:value for field, value in zip(fields, values)}

print(get_fields(("Strength", "Speed", "Stealth", "Cunning")))
Provide as many fields as you like. You can also change the prompt and window tittle. Returns a dictionary.
Reply
#3
Thank you again for your help, I have tried to use your method, it does return a dictionary although I am not sure how to add the ability/values to my dictionary, for it to be displayed -- here is my original code that does not use a multenterbox, if you try "Add Card" in the gui, it takes input and outputs not like {'Strength': 1, 'Speed': 2, 'Stealth': 3, 'Cunning': 4}, instead like

"STONELING MONSTER CARD
Strength: 7
Speed: 1
Stealth: 25
Cunning: 15

In the terminal and the gui. I think the problem is that this is not linked to my nested dictionary, which is why it is not adding it, and this window pops up before the initla displayed options of what the user wants to choose to do.

Here is my full code:

import easygui

card_catalogue = {
  "Stoneling" : {
    "Strength" : 7,
    "Speed" : 1,
    "Stealth" : 25,
    "Cunning" : 15
  },
  "Vexscream" : {
    "Strength" : 1,
    "Speed" : 6,
    "Stealth" : 21,
    "Cunning" : 19
  },
  "Dawnmirage" : {
    "Strength" : 5,
    "Speed" : 15,
    "Stealth" : 18,
    "Cunning" : 22
  },
  "Blazegolem" : {
    "Strength" : 15,
    "Speed" : 20,
    "Stealth" : 23,
    "Cunning" : 6
  },
  "Websnake" : {
    "Strength" : 7,
    "Speed" : 15,
    "Stealth" : 10,
    "Cunning" : 5
  },
  "Moldvine" : {
    "Strength" : 21,
    "Speed" : 18,
    "Stealth" : 14,
    "Cunning" : 5
  },
  "Vortexwing" : {
    "Strength" : 19,
    "Speed" : 13,
    "Stealth" : 19,
    "Cunning" : 2
  },
  "Rotthing" : {
    "Strength" : 16,
    "Speed" : 7,
    "Stealth" : 4,
    "Cunning" : 12
  },
  "Froststep" : {
    "Strength" : 14,
    "Speed" : 14,
    "Stealth" : 17,
    "Cunning" : 4
  },
  "Wispghoul" : {
    "Strength" : 17,
    "Speed" : 19,
    "Stealth" : 3,
    "Cunning" : 2
  }
}

VALUE_MIN =  1

VALUE_MAX = 25  


def display_options(): 

    '''Displays options and gets user to indicate what they want to do''' 

    options = { 

        "Add card": add_combo, 

        "Find card": search, 

        "Delete card": delete, 

        "Output all cards": output_menu, 

        "Exit": leave, 

        } 

 

    get_input = "Y" 

 

    # Loop below continues until user selects "Exit" from options and 

    # get_input is set as "N" 

    while get_input != "N": 

 

        msg = "What would you like to do?" 
        title =  "MENU MAKER OPTIONS" 
        choices = [] 
        for i in options: 
          choices.append(i)
          
        selection = easygui.buttonbox(msg, title, choices) 

 

        # Calls a specific function, based on the user's selection from 

        # the menu. 

        # For example, if user clicks on "Delete" button, it will be 

        # get_input = options[leave()] 

        get_input = options[selection]()

 

def add_combo(): 

  '''Allows user to add a new combo to the menu, as well as the items 

  in the combo and their prices. 

  ''' 

  add_more = "Yes" 

  while add_more == "Yes": 

      combo_name = easygui.enterbox("Enter Monster Card name: ", 

                                      title = "Monster Card Name") 

      name_check = check_exists(combo_name) 

      if name_check == combo_name: 
          easygui.msgbox("That card name has already been used.") 
          break 
      else: 
          combo_name = combo_name.capitalize() 

        

      card_catalogue[combo_name] = {} 

      add_items(combo_name) 

              

      # Checks if user would like to add another combo. 

      msg = "Do you want to add another monster card?" 
      title = "Add card?" 
      choices = ["Yes", "No"] 
      add_more = easygui.buttonbox(msg, title, choices) 

def search(): 

  '''Searches for specified combo in the menu. 



    If the combo is in the menu, the combo details are displayed on 

    screen. Otherwise, the user is told that there is no such combo 

    and given the option to add the combo. 

  ''' 

  msg = "Enter card name:" 
  title = "Card to search for" 
  search = easygui.enterbox(msg, title) 



  # Calls function to check whether the combo already exists 

  combo = check_exists(search) 

  if combo: 

      # Calls function to display combo details on screen. 

      show_menu(combo)


  else: 

      # If the combo does not exist, the user is told this and 

      # given the option to add the combo. 

      msg = "There is no such combo on the menu.\nWould you like to add the combo?" 
      title = "Card does not exist" 
      choices = ["Yes", "No"] 
      add = easygui.buttonbox(msg, title, choices) 

      if add == "Yes": 
        add_combo() # Calls function to add a combo.


def delete(): 

    '''Allows user to delete a combo.''' 

    del_combo = "" 

    while del_combo == "": 

        msg = "Enter name of the card you want to delete." 

        title = "Card to delete" 

        del_combo = easygui.enterbox(msg, title) 

 

        # Calls function to check if the combo entered by user exists. 

        del_combo = check_exists(del_combo) 

         

        # If the combo exists, the user is asked to confirm whether 

        # they want to delete the combo. Otherwise, they are shown an 

        # error message. 

        if del_combo: 

            msg = "Are you sure you want to delete the " + del_combo + " Card?" 

            title = "Confirm delete" 

            choices = ["Yes","No"]  

            sure = easygui.buttonbox(msg, title, choices) 

            if sure == "Yes": 

                card_catalogue.pop(del_combo) 

        else: 

            msg = "That combo is not on the menu." 

            title = "ERROR: Combo not on menu" 

            easygui.msgbox(msg, title) 

            del_combo = "" 

def output_menu(): 

    '''Outputs the full menu to Python Shell (for printing)''' 

    output = ""

    for combo_name, combo_info in card_catalogue.items(): 

        print("\n\n" + combo_name.upper() + " MONSTER CARD") 
        output += f"{combo_name.capitalize()}:\n"

 

        for key in combo_info: 
            price = format(combo_info[key]) 
            print(key + ": " + price)
            output += f"\t{key}: {price}\n"            

        print("_" * 26) 

    easygui.textbox("These are the contents of the card catalogue",
                    "Display All Combos", output) 


def validate_value(value, item): 

    """Input validation: Checks that the user has input a valid value. 

    """ 

    # If the user presses the Cancel button, function is called to  

    # confirm that the user wants to exit. 

    if value == None: 
      
      value = query_cancel() 

 

    # If the user presses the OK button without entering a value, 

    # the no_value() function is called to display an error message 

    # and get input. 

    while value == "": 
      
      value = no_value(item) 

 

    # The while loop checks that input is valid (from VALUE_MIN to  

    # VALUE_MAX), and if not an error message is displayed, and the  

    # user is prompted to re-enter the value. 

    while float(value) < VALUE_MIN or float(value) > VALUE_MAX: 
      
      msg = "Please enter a valid value for " + item + " (from " + str(VALUE_MIN) + " to " + str(VALUE_MAX) + ")." 
      title = "ERROR" 
      value = easygui.enterbox(msg, title) 

 

        # If the user pressed OK without entering a value, the function 

        # is called to display and error message and get input. 

      while value == "": 
        value = no_value(item) 

 

        # If the user presses the Cancel button, function is called to  

        # confirm that the user wants to exit. 

      if value == None: 
        
        value = query_cancel()
        
        return (value) 


def no_value(item): 

    """Input validation: If the user presses the OK button without  

    entering a value, they are shown an error message, and prompted 

    again to enter a value. 

    """ 

    msg = "You must enter a value for " + item + " (from $" + str(VALUE_MIN) + " to $" + str(VALUE_MAX) + ")." 

    title = "ERROR" 

    value = easygui.enterbox(msg, title) 

         

    # If the user presses the Cancel button, function is called to  

    # confirm that the user wants to exit. 

    if value == None: 
      
      value = query_cancel() 
      
      return value 

 

def query_cancel(): 

    """Input validation: If the user presses the Cancel button, they are 

    asked if they are sure they want to exit the current menu item. 

    """ 

    leave = easygui.buttonbox("Do you want to exit?", choices=["Yes", "No"]) 

 

    # If the user confirms they want to exit, they are shown the main 

    # list of options. 

    if leave == "Yes": 

        # Takes back to the main menu or you could simply have exit() 

        display_options() 

    else: 

        # Returns nothing so that the program continues 

        return 0 

 

 

def check_exists(search): 

    '''Checks whether a combo exists (ie is on the menu). 

    ''' 

    for combo_name, combo_info in card_catalogue.items():
      if search.capitalize() == combo_name:
        combo = combo_name
        return(combo)
        break 

def show_menu(name):
  
  '''Displays the details for the combo that has been added.'''
  
  output = ["\n\n***" + name + " Combo details***\n"]
  
  for value in card_catalogue[name]:
    price = format(card_catalogue[name][(value)])
    info = value + ": " + price
    easygui.msgbox(output.append(info))
  
  easygui.msgbox("\n".join(output))

       

def add_items(combo): 

    '''Allows the user to add items to a specified combo.''' 

    msg = "Enter item/s for combo, separated by a comma." 

    title  = "Enter card items" 

    items = easygui.enterbox(msg, title) 

 
    items_list = items.split(",") 

    

    for i in items_list: 

        # Input handling: To handle a situation where the user enters 

        # a space after the comma when entering items. 

        item = i.strip() 

        msg = item + ": Enter Strength/Speed/Stealth/Cunning Value:" 

        title  = item + " Monster Card Value:" 

        card_catalogue[combo][item] = easygui.enterbox(msg, title) 

 

    # Calls function to display combo. 

    show_menu(combo) 

     

def leave(): 

    '''Farewells user if they have chosen to exit the program.''' 

    easygui.msgbox("Thanks for using the menu builder.") 

    return "N" 

 

 

# The main program starts below. 

display_options() 
If you run this program and select add card, you will see what I mean ~ all I am really trying to figure out is how I can do the same thing the enterbox is doing, but instead with a multenterbox that is all in one window, thanks!
Reply
#4
It would get called by add_combo() like this:
def get_fields(msg, title, fields):
    """Get values for multiple fields.  Returns values in dictionry"""
    values = easygui.multenterbox(msg, title, fields)
 
    # make sure that none of the fields were left blank
    while True:
        missing_fields = ", ".join([field for field, value in zip(fields, values) if not value.strip()])
        if missing_fields:
            values = easygui.multenterbox(f"Enter values for {missing_fields}", title, fields, values)
        else:
            return {field:value for field, value in zip(fields, values)}


def add_combo(): 
    '''Add new combo to menu''' 
    while True:
        combo_name = easygui.enterbox(
            "Enter Monster Card name: ",
            title = "Monster Card Name").capitalize()
 
        if check_exists(combo_name): 
            easygui.msgbox("That card name has already been used.") 
        else:
            card_catalogue[combo_name] = get_fields(
                msg="Enter Values",
                title="Monster Card Value",
                fields=("Strength", "Speed", "Stealth", "Cunning"))
 
        if not confirm("Do you want to add another monster card?"):
            break
I notice you use confirm (Yes/No) dialogs in several places in your code. It might make sense to write a function that makes this easier.
def confirm(msg, title="Confirm):
    """Return True if user selects Yes, else return False"""
    choices = ["Yes", "No"]
    return easygui.buttonbox(msg, title, choices) == choices[0]
The check_exists function only returns a value if the name is found, otherwise the default value None is returned. This is a bad practice. If a function ever returns a value it should always return a value.
def check_exists(name): 
    '''Checks whether a combo exists.  Return combo name if found, else None'''
    name = name.capitalize()
    if name in card_catalogue:
        return name
    return None
There is an easier way to build a list of dictionary keys.
def display_options(): 
    '''Displays options and gets user to indicate what they want to do''' 
    options = { 
        "Add card": add_combo, 
        "Find card": search, 
        "Delete card": delete, 
        "Output all cards": output_menu, 
        "Exit": leave}

    # Loop until user selects "Exit" options
    msg = "What would you like to do?",
    title = "MENU MAKER OPTIONS",
    choices = list(options.keys())
    while True: 
        if options[easygui.buttonbox(msg, title, choices)]() == "No":
            break
Reply
#5
I sincerely appreciate your efforts in voluntarily giving me a hand on this, deanhystad, you are truly amazing. I spent countless hours trying to figure how to convert the enterbox to multenterbox, but I just couldn't figure out a solution, many thanks again, wish I could give you +999999 reputation Smile
Reply
#6
Read all the recipes in the easygui documentation. They do a pretty good job explaining how everything works and provide examples for common design patterns. Look at the examples, find the one most similar to what you are trying to do. Copy the pattern.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  easygui use enter instead of ok udihamudi 2 1,987 Oct-04-2020, 01:45 PM
Last Post: deanhystad
  Easygui Izzy32 11 8,410 Jul-12-2018, 11:19 AM
Last Post: Izzy32

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020