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

时间:2021-05-11 17:19:04

标签: python user-interface tkinter

在用户单击按钮后,我想创建一个带有建议的新顶层窗口,当用户在顶层窗口上选择他/她的建议并单击“完成”按钮时,我想销毁顶层窗口并传递选择结果到根窗口。这就是我想要实现的目标,但直到现在我都无法正确完成。

我尝试在顶级窗口上使用 multi trait_mod:<is>(Sub $fn, :$foo!) { for $fn.ast.ast-lexical-declarations { say "Name: " ~ .lexical-name; when RakuAST::VarDeclaration::Simple { #`( my $x / state $x / ... ) } when RakuAST::VarDeclaration::Term { #`( my \x = ... ) } # Others, depending if you care about parameters, placeholder params, implicits, etc. } } 但每次都不起作用,因为有时它不返回任何内容或无限期冻结。

wait_window

2 个答案:

答案 0 :(得分:2)

tkinter 方法 wait_window 完全符合您的要求,不过您也可以使用 wait_visibility 甚至 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

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

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

答案 1 :(得分:0)

好吧,我通过首先检查是否选择了某些东西,然后通过全局引用顶级窗口来销毁顶级窗口来解决它。正如@Bryan Oakley 确认的那样,我还使用 wait_window 等待选择。

最终工作代码:

import tkinter as tk

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

def select():
    global listbox, SUGGESTIONS, selected, toplvlwin

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

def show_suggestions():
    global SUGGESTIONS, listbox, selected, toplvlwin 

    toplvlwin = tk.TopLevel()
    toplvlwin.title("Select suggestion")
    toplvlwin.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) 
    
    toplvlwin.wait_window()

    print(selected) # confirm correct tuple id is returned
    
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()