首页 > 解决方案 > Tkinter 为每个单选按钮返回相同的值?

问题描述

我正在使用 Tkinter 弹出一个自定义对话框。我正在从另一个 Tkinter 窗口打开它。

root = Tk()
class ListDialog:
    def __init__(self, names, prompt):
        self.names = names
        self.sub_root = Tk()
        self.sub_root.title("Intovex")
        self.sub_root.iconbitmap("Icon.ico")
        self.myfont = Font(root=self.sub_root, family="Arial", size=8)
        self.sub_root.maxsize(320, 240)
        self.sub_root.wm_attributes("-topmost", True)
        self.sub_root.wm_attributes("-toolwindow", True)
        self.var = IntVar()
        label = Label(self.sub_root, text=prompt)
        label.pack(fill=X)
        c=1
        print(names)
        for i in names:
            print(i)
            r = Radiobutton(self.sub_root, text=i, variable=self.var, value=c, command=self.end)
            r.pack(anchor=W)
            c+=1
        self.var.set(1)
        button = Button(self.sub_root, command=self.endit, text="OK", bg = "#448DE0", fg="White", bd=0, width=12, pady=4, padx=4, height=1,font=self.myfont, highlightcolor="#A3C7F0")
        button.pack(side=BOTTOM)
        self.choice = names[0]

    def end(self):
        ch = self.var.get()
        print(str(ch))
        self.choice = self.names[ch - 1]

    def endit(self):
        self.sub_root.destroy()

    def ask(self):
        self.sub_root.mainloop()
var2 = StringVar()
def get_choice():
    list = ListDialog(["Test1", "Test2"], "Testing")
    list.ask()
    var2.set(str(list.choice))

label = Label(root, text="", textvariable=var2)
button = Button(root, text="Test", command=get_choice)
label.pack()
button.pack()
root.mainloop()

但是,当它通过直接实例化类并调用 ask() 方法单独运行时,它可以工作。您可能已经看到我在代码中到处都有打印语句(用于调试),我发现它在哪里不起作用

root = Tk()
class ListDialog:
    def __init__(self, names, prompt):
        self.names = names
        self.sub_root = Tk()
        self.sub_root.title("Intovex")
        self.sub_root.iconbitmap("Icon.ico")
        self.myfont = Font(root=self.sub_root, family="Arial", size=8)
        self.sub_root.maxsize(320, 240)
        self.sub_root.wm_attributes("-topmost", True)
        self.sub_root.wm_attributes("-toolwindow", True)
        self.var = IntVar()
        label = Label(self.sub_root, text=prompt)
        label.pack(fill=X)
        c=1
        print(names)
        for i in names:
            print(i)
            r = Radiobutton(self.sub_root, text=i, variable=self.var, value=c, command=self.end)
            r.pack(anchor=W)
            c+=1
        self.var.set(1)
        button = Button(self.sub_root, command=self.endit, text="OK", bg = "#448DE0", fg="White", bd=0, width=12, pady=4, padx=4, height=1,font=self.myfont, highlightcolor="#A3C7F0")
        button.pack(side=BOTTOM)
        self.choice = names[0]

    def end(self):
        ch = self.var.get()
        print(str(ch))
        self.choice = self.names[ch - 1]

    def endit(self):
        self.sub_root.destroy()

    def ask(self):
        self.sub_root.mainloop()
list = ListDialog(["Test1", "Test2"], "Testing")
list.ask()
print(list.choice)

但如果我将它作为 TopLevel 小部件打开,它就可以工作。但是随后主窗口不会等到弹出窗口返回值(选择)。

标签: pythontkinter

解决方案


第一个片段中的代码的问题是因为您在Tk()tkinter 应用程序中调用了更多次 - 它混淆了接口代码并可能导致各种问题,正如您所发现的那样。

如果您将类__init__()方法内的调用替换为ListDialog一个 to tk.Toplevel(),那么您的代码将开始工作。

我还通过更改它来简化for创建Radiobuttons 的循环,以便使用内置enumerate()函数自动保留名称的计数。与此相结合,我设置了IntVar 的初始值,这不是选择单选按钮将分配给它的值之一。因此,当第ListDialog一次显示时,它们都不会被选中。它还确保end()当用户按下其中一个时回调函数将被调用,因此您的应用程序将始终在发生这种情况时得到通知。

请注意,虽然我没有更改它,但您不应该命名变量list,因为这会隐藏该名称的内置类的名称。一般来说,你应该避免命名任何与现有标准 Python 名称冲突的东西。

from tkinter import *
from tkinter.font import Font

root = Tk()

class ListDialog:
    def __init__(self, names, prompt):
        self.names = names
#        self.sub_root = Tk()  # Wrong - don't call Tk() more than once.
        root.withdraw()  # Hide root window.
        self.sub_root = Toplevel()  # Create another top-level window.
        self.sub_root.title("Intovex")
#        self.sub_root.iconbitmap("Icon.ico")  # I don't have this file...
        self.myfont = Font(root=self.sub_root, family="Arial", size=8)
        self.sub_root.maxsize(320, 240)
        self.sub_root.wm_attributes("-topmost", True)
        self.sub_root.wm_attributes("-toolwindow", True)
        self.var = IntVar(value=0)  # Define and init value to one *not* produced by btns.
        label = Label(self.sub_root, text=prompt)
        label.pack(fill=X)
        print(names)
        for c, name in enumerate(names, start=1):
            print(c)
            r = Radiobutton(self.sub_root, text=c, variable=self.var, value=c,
                            command=self.end)
            r.pack(anchor=W)

        button = Button(self.sub_root, command=self.endit, text="OK", bg = "#448DE0",
                        fg="White", bd=0, width=12, pady=4, padx=4, height=1,
                        font=self.myfont, highlightcolor="#A3C7F0")
        button.pack(side=BOTTOM)
        self.choice = names[0]

    def end(self):
        ch = self.var.get()
        print(str(ch))
        self.choice = self.names[ch - 1]

    def endit(self):
        self.sub_root.destroy()
        root.deiconify()  # Reshow root window.

    def ask(self):
        self.sub_root.mainloop()

var2 = StringVar()

def get_choice():
    list = ListDialog(["Test1", "Test2"], "Testing")
    list.ask()
    var2.set(str(list.choice))

label = Label(root, text="", textvariable=var2)
button = Button(root, text="Test", command=get_choice)
label.pack()
button.pack()
root.mainloop()

推荐阅读