简体   繁体   中英

How to return the selected items of a listbox when using wait_window() in tkinter

I would like my tkinter application to return the selected items of a listbox from a called window (class MyDialog ) to the calling window (class Example ). If I do not use wait_window(), an empty list is returned. Using wait_window() results in an error message. It seems to me that wait_window() blocks the curselection() method. What needs to be changed for a proper return?

The example below is a modified version of this answer .

import tkinter as tk

class MyDialog(object):
    def __init__(self, parent):
        self.toplevel = tk.Toplevel(parent)

        choices = ("one", "two","three")
        names = tk.StringVar(value=choices)

        label = tk.Label(self.toplevel, text="Pick something:")
        self.listbox = tk.Listbox(self.toplevel, listvariable=names, height=3,
            selectmode="single", exportselection=0)
        button = tk.Button(self.toplevel, text="OK", command=self.toplevel.destroy)

        label.pack(side="top", fill="x")
        self.listbox.pack(side="top", fill="x")
        button.pack()

    def show(self):
        self.toplevel.wait_window()

        value = self.listbox.curselection()
        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, width=80)
        self.label.pack(side="top", fill="x")
        self.button.pack(pady=20)

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

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

wait_window waits until the widow is destroyed . And since it is destroyed, you can't pull any information out of the widget.

You must set up bindings that save the data to a variable when it changes, so that you can fetch it after the widget is destroyed.

Bryan Oakley's answer led me to the solution posted below. Thank you very much!

import tkinter as tk

class MyDialog(object):
    def __init__(self, parent):
        self.toplevel = tk.Toplevel(parent)

        choices = ("one", "two","three")
        names = tk.StringVar(value=choices)

        label = tk.Label(self.toplevel, text="Pick something:")
        self.listbox = tk.Listbox(self.toplevel, listvariable=names, height=3,
            selectmode="single", exportselection=0)
        button = tk.Button(self.toplevel, text="OK", command=self.toplevel.destroy)

        label.pack(side="top", fill="x")
        self.listbox.pack(side="top", fill="x")
        button.pack()

        # add binding
        self.listbox.bind('<<ListboxSelect>>', self.getSelection)

    # function associated with binding
    def getSelection(self, event):
        widget = event.widget
        selection=widget.curselection()
        self.value = widget.get(selection[0])

    # separate function for wait_window and the return of the selection
    def returnValue(self):
        self.toplevel.wait_window()
        return self.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, width=80)
        self.label.pack(side="top", fill="x")
        self.button.pack(pady=20)

    def on_click(self):
        result = MyDialog(self).returnValue()
        self.label.configure(text="your result: %s" % result)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM