Domanda

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.

È stato utile?

Soluzione

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())
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top