John Iselin
John Iselin

Reputation: 1

How to implement listener using tkinter?

I am trying to develop a dialog box to be used with tkinter that has an entry box and a button. I want to be able to enter a value in the entry box and have the entered value "returned" when the dialog is destroyed. The following code works, but does not perform as I've described. There are two buttons on the gui. The first launches the dialog box and the second retrieves the entered value. I wish to eliminate the second button and have a listener activate the getValues method when the "Save Input" button in the dialog is pressed. Here is the code:

from tkinter import *

class myDialog():
    def __init__(self):
        self.t = Toplevel()
        self.t.title("Sample")
        self.answer = None
        self.v1 = StringVar()
        self.e1 = Entry(self.t, textvariable=self.v1)
        self.e1.focus()
        self.e1.pack()
        self.saveButton = Button(self.t, text="Save Input", command=self.buttonPressed)
        self.saveButton.pack()

    def buttonPressed(self):
        print("Popup Button Pressed")
        self.answer = self.e1.get()
        self.t.destroy()

class myTk(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.button = Button(text="Display Dialog", command = self.displayPopButton)
        self.button.pack()
        self.getButton = Button(text="Print Values", command=self.getValues)
        self.getButton.pack()

    def displayPopButton(self):
        self.b1 = myDialog()

    def getValues(self):
        print(self.b1.answer)

myTk().mainloop()

Upvotes: 0

Views: 128

Answers (2)

acw1668
acw1668

Reputation: 47173

You can make myDialog a modal dialog using grab_set() and wait_window():

from tkinter import *

class myDialog():
    def __init__(self):
        self.t = Toplevel()
        self.t.title("Sample")
        self.answer = None
        self.v1 = StringVar()
        self.e1 = Entry(self.t, textvariable=self.v1)
        self.e1.focus()
        self.e1.pack()
        self.saveButton = Button(self.t, text="Save Input", command=self.buttonPressed)
        self.saveButton.pack()
        # handle user clicking the 'x' button at the title bar
        self.t.protocol('WM_DELETE_WINDOW', self.buttonPressed)

    def buttonPressed(self):
        print("Popup Button Pressed")
        self.answer = self.e1.get()
        self.t.destroy()

    def show(self):
        # make the toplevel act like a modal dialog
        self.t.grab_set()
        self.t.wait_window(self.t)
        # return the answer when the toplevel is closed/destroyed
        return self.answer

class myTk(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.button = Button(text="Display Dialog", command = self.displayPopButton)
        self.button.pack()

    def displayPopButton(self):
        self.b1 = myDialog().show()
        print(self.b1)

myTk().mainloop()

Upvotes: 0

r.ook
r.ook

Reputation: 13898

You could be passing in your main object as a param in your Dialog, and call the master method within the buttonPressed method:

class myDialog():
    def __init__(self, master):
        self.t = Toplevel()
        self.master = master
        # ... #

    def buttonPressed(self):
        print("Popup Button Pressed")
        self.answer = self.e1.get()
        self.master.getValues()
        self.t.destroy()

class myTk(Tk):
    # ... #
    def displayPopButton(self):
        self.b1 = myDialog(self)

This achieves what you want, but personally I don't think it's good OOP. It makes your Dialog reliant on having the expected master type and the required method. You could organize it a little differently to be more explicit::

class myDialog():
    def __init__(self, func_to_call):
        self.t = Toplevel()
        self.btn_func = func_to_call
        # ... #

    def buttonPressed(self):
        print("Popup Button Pressed")
        self.answer = self.e1.get()
        func_to_call()
        self.t.destroy()

class myTk(Tk):
    # ... #
    def displayPopButton(self):
        self.b1 = myDialog(self.getValues)

In any case, I would at least subclass myDialog as a Toplevel. And perhaps rethink how I want the objects to refer to each other.

Upvotes: 1

Related Questions