简体   繁体   中英

Tkinter: all radio buttons are selected

弹出窗口的屏幕快照,其中显示了大多数预选的单选按钮

Why in this code when clicking a button when a new window opens, all the radio buttons are selected?

class CodeButton:
    def __init__(self, root):
        self.btn = Button(root, text="Code",width=20, height=1,bg="white", fg="black")
        self.btn.bind("<Button-1>", make_code_window)
        self.btn.pack() 


def make_code_window(event):
    new_root = Toplevel()
    new_root.minsize(width=300, height=300)
    var = IntVar()
    var.set(0)
    for i in range(8):
        Radiobutton(new_root, text=str(i), variable=var, value=i).pack()


def main():
    root = Tk()
    root.minsize(width=400, height=250)
    CodeButton(root)
    root.mainloop()

It's got something to do with storing the IntVar in a local variable in the function that will be discarded as soon as the make_code_window() function returns. You can fix the problem by making the IntVar an attribute of the new_root window widget, so it will exist at least as long as the widget using it does.

The code in your example isn't very realistic in the sense that typically one would want to use the current value of the IntVar for something somewhere else in the Python code, but that wouldn't be possible since it's only stored temporarily in local variable which exists only during the execution of the function that created it.

try:
    from tkinter import *
except ImportError:  # Python 2
    from Tkinter import *

class CodeButton:
    def __init__(self, root):
        self.btn = Button(root, text="Code",width=20, height=1,bg="white", fg="black")
        self.btn.bind("<Button-1>", make_code_window)
        self.btn.pack()


def make_code_window(event):
    new_root = Toplevel()
    new_root.minsize(width=300, height=300)
    var = new_root.var = IntVar()  # changed
    var.set(0)
    for i in range(8):
        Radiobutton(new_root, text=str(i), variable=var, value=i).pack()


def main():
    root = Tk()
    root.minsize(width=400, height=250)
    CodeButton(root)
    root.mainloop()

main()

( Following-up on the discussion we were having in the comments section of my other answer . )

Yes, passing the IntVar as an argument to the event handler function is a little tricky—in fact it's sometimes called The extra arguments trick . ;-)

Here's an example of applying it to your code:

try:
    from tkinter import *
except ImportError:  # Python 2
    from Tkinter import *


class CodeButton:
    def __init__(self, root):
        self.btn = Button(root, text="Code",width=20, height=1,bg="white", fg="black")
        self.btn.bind("<Button-1>",
                      # Extra Arguments Trick
                      lambda event, var=root.var: make_code_window(event, var))
        self.btn.pack()


def make_code_window(event, var):  # note added "var" argument
    new_root = Toplevel()
    new_root.minsize(width=300, height=300)
    var.set(-99)  # deselect by using value not associated with any RadioButtons
    for i in range(8):
        Radiobutton(new_root, text=str(i), variable=var, value=i).pack()

def main():
    root = Tk()
    root.minsize(width=400, height=250)
    root.var = IntVar()  # create it here to give access to it in the rest of your code
    CodeButton(root)
    root.mainloop()

main()

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