如何在继续之前等待 Tkinter TopLevel 窗口的结果?

Lin*_*der 1 python user-interface tkinter

用户单击按钮后,我想创建一个包含建议的新顶级窗口,当用户在顶级窗口上选择他/她的建议并单击“完成”按钮时,我想销毁顶级窗口并将所选结果传递给根窗口。这就是我想要实现的目标,但到目前为止我还无法正确地做到这一点。

我尝试wait_window在顶层窗口上使用,但这并不是每次都有效,因为有时它不会返回任何内容或无限期冻结。

import tkinter as tk

root = None
BTN = None
listbox = None
selected = None
SUGGESTIONS = [(0, "level 1"), (11, "level 2"), (23, "level 3")]

def select():
    global listbox, SUGGESTIONS, selected

    selected = listbox.get(tk.ANCHOR)
    for (idd, info) in SUGGESTIONS:
        if selected == f_info:
                selected = idd

def show_suggestions():
    global SUGGESTIONS, listbox

    win = tk.TopLevel()
    win.title("Select suggestion")
    win.geometry("400x400")
    
    listbox = tk.Listbox(win, height=20, width=40)
    listbox.pack(pady=15)

    self.btn = tk.Button(win, text="Confirm selection", command=select)
    self.btn.pack(pady=10)

    for (idd, info) in SUGGESTIONS :
        self.listbox.insert(tk.END, f_info) 
    
    #TODO: wait for selected suggestion and assign it to global variable selected

def main():
    global root, BTN
    root = tk.Tk()
    root.title("Youtube to MP3")
    root.geometry("575x475")

    BTN = tk.Button(
        master=root,
        text="List suggestions",
        width=25,
        height=5,
        command=show_suggestions
    )
    BTN.pack(pady=15)
    
    root.mainloop()
Run Code Online (Sandbox Code Playgroud)

Bry*_*ley 5

tkinter 方法wait_window完全符合您的要求,尽管您也可以使用wait_visibilityor wait_variable。你声称wait_window不可靠,但这种方法几十年来一直是 tk 的一部分,我个人从未见过它行为不当。

我建议使用两段代码来实现这一点:一个实现窗口本身的类,以及一个使用该类显示窗口并返回所选项目的函数。

下面给出一个例子。请注意,该值self.selection被初始化为None,然后在用户单击“确认选择”按钮时设置为一个值。另请注意,该show方法将在销毁小部件之前获取此值,以便即使在小部件被销毁后也可以检索该值。

class SuggestionPopup(tk.Toplevel):
    def __init__(self, parent, suggestions):
        super().__init__(parent)

        self.title("Select suggestion")

        self.listbox = tk.Listbox(self, height=10, width=20)
        self.listbox.pack(pady=15)

        self.btn = tk.Button(self, text="Confirm selection", command=self.select)
        self.btn.pack(pady=10)

        for (idd, info) in suggestions :
            self.listbox.insert(tk.END, info)

        self.selection = None

    def select(self):
        selection = self.listbox.curselection()
        if selection:
            self.selection = self.listbox.get(selection[0])
        self.destroy()

    def show(self):
        self.deiconify()
        self.wm_protocol("WM_DELETE_WINDOW", self.destroy)
        self.wait_window(self)
        return self.selection
Run Code Online (Sandbox Code Playgroud)

显示它的函数可能看起来像这样:

def get_suggestion():
    suggestions = ((0, "Item 0"), (1, "Item 1"), (2, "Item 2"))
    popup = SuggestionPopup(root, suggestions)
    result = popup.show()
    return result
Run Code Online (Sandbox Code Playgroud)