0

I am trying to create a drop down selection for a personal program, that auto updates the name being shown based on the selected item.

The thing is, regardless of what is selected or what the default value should be, it always auto changes the selected name to the last option the user can choose and it will not change if another option is selected.

import tkinter
from tkinter import *


def changename(name=str):
    selectedText.set(name)
    mb.grid(row=1,column=1)
def startmainloop(var):
    var.mainloop()



root = Tk()

label0=Label(root,text=".....")
label0.grid(row=0,columnspan=2)

selectedText=StringVar()
selectedText.set("Select Race")
mb=Menubutton(root, textvariable=selectedText,relief=GROOVE)
label1=Label(root, text="RACE")
label1.grid(row=1,column=0)
mb.grid()
mb.menu=Menu(mb, tearoff=0)

mb.menu.add_command(label="Argonian", command=changename("Argonian"))
mb.menu.add_command(label="Khajiit", command=changename("Khajiit"))

mb["menu"]=mb.menu

startmainloop(root)

In the image that would be above, the default that it should be showing is "Select Race". A drop down menu appears after clicking on Select Race with the two command options "Argonian" and "Khajiit". After clicking on the option "Argonian", the "Select Race" label of the menu should change to "Argonian". The option "Khajiit" though seems to be overloading the default and won't change regardless of the user selecting Argonian.

3
  • Do you get any errors about not being able to call Nonetype? Commented Jul 29, 2015 at 3:04
  • not if i format it like this, if i put the "StringVar()" before the "root=Tk()" then yeah i got that error Commented Jul 29, 2015 at 6:16
  • You should be getting such an error from command=changename("Argonian") when you select that menu option, because it'll try to call None, which doesn't work. Commented Jul 29, 2015 at 6:19

1 Answer 1

1

When you specify the argument value this way command=changename("Khajiit") it calls the function right then and its return value (None) is passed as the argument value. This is a very common Tkinter programming mistake.

Do something like this instead:

mb.menu.add_command(label="Argonian", command=lambda: changename("Argonian"))
mb.menu.add_command(label="Khajiit", command=lambda: changename("Khajiit"))

This will make the values passed as the command argument anonymous functions that call your handler function with the right argument.

An arguably better, as in more generic and less repetitive approach, would be to modify the changename() function so it retrieved the label of the command itself, then you would only need to specify the string once.

In other words, do something like this:

def changename(index):
    name = mb.menu.entrycget(index, "label")
    selectedText.set(name)
    mb.grid(row=1, column=1)

Which would allow you to just pass the index of the item:

mb.menu.add_command(label="Argonian", command=lambda: changename(0))
mb.menu.add_command(label="Khajiit", command=lambda: changename(1))

To avoid needing to explicitly count and hardcode the index of each command, this could be done in a for loop:

for i, label in enumerate(["Argonian", "Khajiit"]):
    mb.menu.add_command(label=label, command=lambda: changename(i))
Sign up to request clarification or add additional context in comments.

2 Comments

I'm using Python 3.4.3, so is there another way I should be formatting the "command=lambda event: changename(..." I am getting this error using it with your syntax Exception in Tkinter callback Traceback (most recent call last): File "C:\....", line 1533, in call TypeError: <lambda>() missing 1 required positional argument: 'event'
Oops, sorry, I was thinking of widget event handlers which automatically get passed an event argument when they're called. An added menu command's item's command argument is just a procedure to be will be called (with no arguments) whenever the menu item is picked. See updated answer (which now also includes an alternative).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.