Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
351 views
in Technique[技术] by (71.8m points)

python - How to wait for result from Tkinter TopLevel window before continuing?

After a user clicks on a button, I want to create a new TopLevel window with suggestions and when user selects his/her suggestion on the toplevel window and clicks the button "Done" I want to destroy the toplevel window and pass the selected result to root window. This is what I want to achieve but until now I am not able to do it properly.

I tried using wait_window on the toplevel window but that didn't work every time as sometimes it does not return anything or freezes indefinitely.

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()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The tkinter method wait_window does exactly what you want, though you could also use wait_visibility or even wait_variable. You claim wait_window is unreliable but that method has been a part of tk for decades and I've personally never seen it misbehave.

I recommend implementing this with two pieces of code: a class that implements the window itself, and a function which uses the class to display the window and return the selected item.

The following gives an example. Notice that the value self.selection is initialized to None, and then set to a value when the user clicks the "Confirm Selection" button. Also notice that the show method will get this value before destroying the widget so that it can be retrieved even after the widget has been destroyed.

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

The function to display it might look something like this:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...