Question

I am attempting to implement a dialog that gets the users password. I have created the class PasswordDiaglog that inherits from tk.Toplevel but this causes the problem that it's execution is non-blocking of the parent frame.

import Tkinter as tk

class PasswordDialog(tk.Toplevel):
    def __init__(self, parent):
        tk.Toplevel.__init__(self)
        self.password = None
        self.entry = tk.Entry(self, show='*')
        self.entry.pack()
        self.button = tk.Button(self)
        self.button["text"] = "Submit"
        self.button["command"] = self.StorePass
        self.button.pack()

    def StorePass(self):
        self.password = self.entry.get()
        self.destroy()
        print '1: Password was', self.password

class MainApplication(tk.Frame):
    def __init__(self, root):
        tk.Frame.__init__(self, root)
        self.button = tk.Button(self)
        self.button["text"] = "Password"
        self.button["command"] = self.GetPassword
        self.button.pack()

    def GetPassword(self):
        passwd = PasswordDialog(self)
        # HALT HERE 
        print '2: Password was', passwd.password

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

By running my code a submitting foobar as the password the following output is seen in the terminal:

2: Password was None
1: Password was foobar

The expected output should be:

1: Password was foobar
2: Password was foobar

Any ideas on how to solve this or how to implement a password dialog in general?

It would also be nice to call StoredPass() by hitting return after typing in the entry.

Was it helpful?

Solution

Storing the password as attribute of the MainAplication class and using the passed in parent as the handle from the PasswordDialog class means you can use self.wait_window(PasswordDialog(self)) to block the execution until the PasswordDialog is destroyed:

import Tkinter as tk

class PasswordDialog(tk.Toplevel):
    def __init__(self, parent):
        tk.Toplevel.__init__(self)
        self.parent = parent
        self.entry = tk.Entry(self, show='*')
        self.entry.bind("<KeyRelease-Return>", self.StorePassEvent)
        self.entry.pack()
        self.button = tk.Button(self)
        self.button["text"] = "Submit"
        self.button["command"] = self.StorePass
        self.button.pack()

    def StorePassEvent(self, event):
        self.StorePass()

    def StorePass(self):
        self.parent.password = self.entry.get()
        self.destroy()
        print '1: Password was', self.parent.password

class MainApplication(tk.Frame):
    def __init__(self, root):
        tk.Frame.__init__(self, root)
        self.password = None
        self.button = tk.Button(self)
        self.button["text"] = "Password"
        self.button["command"] = self.GetPassword
        self.button.pack()

    def GetPassword(self):
        self.wait_window(PasswordDialog(self))
        print '2: Password was', self.password

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

The output is now as expected:

1: Password was foobar
2: Password was foobar

To bind the Return key you can use:

self.entry.bind("<KeyRelease-Return>", self.StorePassEvent)

With a wrapper function:

def StorePassEvent(self, event):
    self.StorePass()

You can also use lambda instead:

self.entry.bind("<KeyRelease-Return>", lambda x: self.StorePass())
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top