Question

As a way to introduce myself to Python I've decided to replicate the basic calculator that comes with Windows. I've managed to solve the initial problem of naming individual buttons created through a loop with variables stored in an array by using the vars() function (somewhat scrappy, I know). However, this doesn't work when I encapsulate the loop within a function.

Array:

controls = [
    ["zer", "0", 0, 18, 150, 30, 70],
    ["one", "1", 1, 18, 115, 30, 35],
    ["two", "2", 2, 54, 115, 30, 35]
]

This works:

for b in controls:
    vars()[b[0]] = Button(calc, text=b[1], command=lambda inp=b[2]:click(inp))
    vars()[b[0]].place(x=b[3], y=b[4], height=b[5], width=b[6])

This returns a NameError when trying to adjust the state of one of the buttons:

def setButtons(buttons)
    for b in buttons:
        vars()[b[0]] = Button(calc, text=b[1], command=lambda inp=b[2]:click(inp))
        vars()[b[0]].place(x=b[3], y=b[4], height=b[5], width=b[6])

setButtons(controls)

I know the array's being passed to the function since the buttons still generate and behave fine. This is the exact problem I had before using the vars() function, so I'm guessing this will be a problem with scoping. I should also note that I have yet to look into the use of dictionaries, which I'm worried may solve this problem completely and eliminate the need to use vars().

Anyone have any ideas?

Was it helpful?

Solution

There's no reason to use vars. The simple solution is to store all the widgets in a dictionary:

self.buttons = {}
for b in controls:
    self.buttons[b[0]] = Button(...)

There's also no good reason to use place -- place has it's advantages but they are few and far between. Your GUI will be much easier to write and maintain if you use pack or grid. In the case of a calculator, grid is a very natural choice. Also, trying to define the layout in a data structure is cumbersome. I'm not sure there's any real value to it since it's unlikely you're going to be creating a generic algorithm that can create calculators with different numbering systems.

I recommend separating the layout of the widgets from the creation of the widgets. In my experience that simply makes GUI development easier.

self.buttons["zer"].grid(row=3, column=0, columnspan=2, sticky="nsew")
self.buttons["two"].grid(row=2, column=0, sticky="nsew")
self.buttons["thr"].grid(row=2, column=1, sticky="nsew")
...

Also, I'd suggest not using names like "zer" -- there's really no value in abbreviating a four letter word to three letters.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top