阻塞式输入对话框

3

如何在标准Python中获得一个阻塞模态输入对话框?

我需要用户在代码继续执行之前输入一个值。

以下是一些不起作用的测试代码,但这个想法是我应该能够从脚本的任何地方调用MyDialog,所以这只是一个简化的例子。

import tkinter

class MyDialog:
    def __init__(self, prompt):
        self.top = tkinter.Toplevel()
        tkinter.Label(self.top, text=prompt).pack()
        self.e = tkinter.Entry(self.top)
        self.e.pack(padx=5)
        tkinter.Button(self.top, text="OK", command=self.ok).pack(pady=5)

    def ok(self):
        self.top.destroy()
        return self.e.get()


root = tkinter.Tk()
userName = MyDialog('Enter your name')
tkinter.Label(root, text="Hello {}".format(userName)).pack()

root.mainloop()

对话框不仅应该禁用主窗口,还应该阻止调用它的任何代码。并且它应该能够将值传递回调用代码。

可能是 禁用 Python TKinter 中弹出窗口时的底层窗口 的重复问题。 - Steven Summers
@StevenSummers 那个解决方案没有提供代码阻塞。 - mcu
你能否澄清一下哪些代码会被阻止,以及会传回什么样的值?例如,如果一个按钮打开了“MyDialog”,那么是否会阻止该按钮再次打开? - Steven Summers
直到用户关闭对话框,才应执行行tkinter.Label(root...),此时您将在userName中获得用户提供的值。 - mcu
你不能在按钮单击事件中创建它吗?把它放在事件外面似乎很奇怪。 - Steven Summers
你的意思是创建 userName 吗?但这仍然无法阻止代码。 - mcu
1个回答

3
解决方案需要两个关键部分。首先,使用grab_set来阻止其他窗口中的所有事件(或更正确地说,将所有事件发送到对话框窗口)。其次,使用wait_window来防止方法在对话框销毁之前返回。
话虽如此,你不应该像你的示例那样使用它。在创建窗口之前,必须让mainloop运行。它可能在某些平台上正常工作,但一般情况下,在mainloop运行之前不能指望GUI表现正常。
以下是一个简单的示例:
import Tkinter as tk

class MyDialog(object):
    def __init__(self, parent, prompt):
        self.toplevel = tk.Toplevel(parent)
        self.var = tk.StringVar()
        label = tk.Label(self.toplevel, text=prompt)
        entry = tk.Entry(self.toplevel, width=40, textvariable=self.var)
        button = tk.Button(self.toplevel, text="OK", command=self.toplevel.destroy)

        label.pack(side="top", fill="x")
        entry.pack(side="top", fill="x")
        button.pack(side="bottom", anchor="e", padx=4, pady=4)

    def show(self):
        self.toplevel.grab_set()
        self.toplevel.wait_window()
        value = self.var.get()
        return value

class Example(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.button = tk.Button(self, text="Click me!", command=self.on_click)
        self.label = tk.Label(self, text="", width=40)
        self.label.pack(side="top", fill="x")
        self.button.pack(padx=20, pady=20)

    def on_click(self):
        result = MyDialog(self, "Enter your name:").show()
        self.label.configure(text="your result: '%s'" % result)

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

很好。我只希望这已经成为tkinter的一部分,有点像tkinter.messagebox。但这样更具可定制性。 - mcu
@coding4fun:这种类型的对话框是 tkinter 的一部分。它被称为 askstring - Bryan Oakley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接