简体   繁体   中英

Python3 - Tkinter - Widget creation with a dict

Im trying to create widgets dynamically onto the root window of tkinter with a json file as a widget config. I simplified the code so you can also test things out. (Im using grid() in my main code but its not necessary here)

The json file contains an items list with each widget in a seperate dict, it can look for example like this.

new_dict = {
    "items": [
        {
            "type": "frame",
            "id": "f1"
        },
        {
            "type": "button",
            "id": "b1",
            "text": "Button1"
        }
    ]
}

My goal here to create a widget, stored in the value of the id field, so i can later on change widgets states or other things via .config()

( Example: f1 = Frame(root) )

For this example my code looks like this:

( Note: im using locals() to create the specific variables, if there is a better way, please let me know )

# Example: Change Frame Color to Blue
def change_background(frame_id):
    locals()[frame_id].config(bg=blue)

# Root Window
root = Tk()
root.geometry("800x600")

# Widget Creation
for item in new_dict["items"]:
    if item["type"] == "frame":
        frame_id = item["id"]
        locals()[item["id"]] = Frame(root, width=200, height=200, bg="green")
        locals()[item["id"]].pack(side=BOTTOM, fill=BOTH)
    elif item["type"] == "button":
        locals()[item["id"]] = Button(root, text=item["text"], command=lambda: change_background(frame_id))
        locals()[item["id"]].place(x=50, y=50, anchor=CENTER)

root.mainloop()

Now my problem here is that i cant give the frame id into the change_background function. If i do that im getting following Error:

KeyError: 'f1'

I dont quite understand the problem here, because pack() , place() and grid() works fine with each widget.

As what the name locals means, it stores only local variables. So locals() inside the function just contains local variables defined inside the function.

It is not recommended to use locals() like this. Just use a normal dictionary instead:

...
# Example: Change Frame Color to Blue
def change_background(frame_id):
    widgets[frame_id].config(bg="blue")

# Root Window
root = Tk()
root.geometry("800x600")

# Widget Creation
# use a normal dictionary instead of locals()
widgets = {}
for item in new_dict["items"]:
    if item["type"] == "frame":
        frame_id = item["id"]
        widgets[item["id"]] = Frame(root, width=200, height=200, bg="green")
        widgets[item["id"]].pack(side=BOTTOM, fill=BOTH)
    elif item["type"] == "button":
        widgets[item["id"]] = Button(root, text=item["text"], command=lambda: change_background(frame_id))
        widgets[item["id"]].place(x=50, y=50, anchor=CENTER)
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM