Question

I've been experimenting with Tkinter, and I have a set-up where I have an entry box and then below it two buttons (Close and OK). When close is clicked, the frame is destroyed. I want it to return whatever is in the entry box at the time and then destroy the frame. I am just at a loss for how to do this.

This is a portion of what I have (where f is my frame):

class App:
    def DoThis(self):
        #Earlier code that's not related to the question
        v=StringVar()
        e=Entry(f,textvariable=v)
        buttonA=Button(f,text="Cancel",command=root.destroy)
        buttonB=Button(f,text="OK")

Also, please note that I want to RETURN the string to the calling function, not just immediately print it.

I want:

print App().DoThis() #to print what was in the entry box
#at the time of OK being clicked
Was it helpful?

Solution

What you ask is, for all intents and purposes, impossible. The function DoThis will return before the GUI even displays on the screen.

That being said, such a thing is possible, though highly unusual. It's a bit like asking how you can haul a bale of hay across a muddy field in a Ferrari.

If you just plan on popping up a window once, you can get by with something like the following:

import Tkinter as tk

class MyApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.entry = tk.Entry(self)
        self.entry.pack()
        close_button = tk.Button(self, text="Close", command=self.close)
        close_button.pack()
        self.string = ""

    def close(self):
        global result
        self.string = self.entry.get()
        self.destroy()

    def mainloop(self):
        tk.Tk.mainloop(self)
        return self.string

print "enter a string in the GUI"
app = MyApp()
result = app.mainloop()
print "you entered:", result

If you are going to open the window more than once you're probably not going to have much luck because, again, this just isn't how Tkinter is designed to be used.

OTHER TIPS

at the moment you're assigning ButtonA, Cancel, command to root.destroy. Instead of directly calling the destroy function, create a separate function that reads the value then calls destroy.

I usually wrap this in a Frame class to make it a little easier:

import Tkinter

class Frame(Tkinter.Frame):

def __init__(self, root=None):
    self.root = root
    Tkinter.Frame.__init__(self, root)

    # Create widgets
    self.v = StringVar()
    self.e = Entry(self, textvariable=v)
    self.buttonA = Button(self, text="Cancel", command=cancel)
    self.buttonB = Button(self, text="OK")

def cancel(self):
    print self.v.get()  # handle value here
    self.root.destroy()

Basically, you want your callback function from the button to be a bit more complicated. Rather than simply calling the destroy method, you'll want to call your own function. Use the get method on the Entry object to retrieve the contents.

Hopefully this is a complete enough example to get you going:

import Tkinter as tk

class App:
    def __init__(self, master):
        self.display_button_entry(master)

    def setup_window(self, master):
        self.f = tk.Frame(master, height=480, width=640, padx=10, pady=12)
        self.f.pack_propagate(0)

    def display_button_entry(self, master):
        self.setup_window(master)
        v = tk.StringVar()
        self.e = tk.Entry(self.f, textvariable=v)
        buttonA = tk.Button(self.f, text="Cancel", command=self.cancelbutton)
        buttonB = tk.Button(self.f, text="OK", command=self.okbutton)
        self.e.pack()
        buttonA.pack()
        buttonB.pack()
        self.f.pack()

    def cancelbutton(self):
        print self.e.get()
        self.f.destroy()

    def okbutton(self):
        print self.e.get()


def main():
    root = tk.Tk()
    root.title('ButtonEntryCombo')
    root.resizable(width=tk.NO, height=tk.NO)
    app = App(root)
    root.mainloop()

main()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top