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()
Advertisement
Answer
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