Python: Assign a function to a dynamically created radio button

Question:

I am new to python and have a task to take input from a listbox and create radiobuttons for each entry. In my code I am able to create the radio buttons but they don’t function when I click on them i.e. in this case they don’t print “hello” and the number i. Here’s the code:

def generateGraph():
    w = Toplevel(bg = "grey")
    w.resizable(0,0)
    frameData = Frame(w, bg="grey", padx=10, pady=10)
    frameData.grid(row = 0, column=0, pady = 1, padx = 1, sticky = N+E+S+W)
    InputLabel = Label(frameData, text="Inputs:", bg="grey")
    InputLabel.grid(row=1, column=0, padx=10, sticky=N+E+S+W)
    OutputLabel = Label(frameData, text="Outputs:", bg="grey")
    OutputLabel.grid(row=1, column=1, padx=10, sticky=N+E+S+W)

    i=0
    c=[]
    inputVar = IntVar()
    while(InputBox.get(i)):
        c.append(Radiobutton(frameData, text=InputBox.get(i), variable=inputVar, value = i, background="grey", command= hello(i)))
        c[i].grid(row = i+2, column = 0, sticky = W)
        i=i+1
    if makemodal:
        w.focus_set()
        w.grab_set()
        w.wait_window()
def hello(i):
    print("hello %d" %i)

Please help and thanks in advance.

Asked By: Vishesh

||

Answers:

The problem is that you’re calling hello(i) at the time of construction of the Radiobutton, not storing something to be called later:

    c.append(Radiobutton(frameData, text=InputBox.get(i), variable=inputVar, value = i, background="grey", command= hello(i)))

Since hello returns None, you’re effectively storing command=None.

You need to store a callable here, like hello itself, (or a lambda or partial, or whatever), not the result of calling it.

For example:

    c.append(Radiobutton(frameData, text=InputBox.get(i), 
                         variable=inputVar, value = i, background="grey",
                         command=functools.partial(hello, i)))

Since you asked in the comments: Note that I used partial rather than lambda, because I want to bind in the value of i, not close over the variable i. Otherwise, you’d end up with, e.g., 5 radio buttons all bound to the same variable i with the value 4. There are other ways around this—use an explicit factory, do lambda x=i: hello(x) instead of lambda: hello(i), etc. To me, partial seems like the clearest and most explicit, but your mileage may vary. Anyway, there are dozens of questions on SO about this, but the answer to Scope of python lambda functions and their parameters seems particularly clear.

Answered By: abarnert
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.