Search code examples
pythontkinter

Transient input window


I have a system, where there is a popup window that requests input from the user, and then returns that input to the main body of code for processing. I have the window popping up correctly, using transient to ensure it stays on top, however I cannot find a way to make the window return data to the place it was called from. Current:

from tkinter import *

class LoginWindow(object):
    def __init__(self, parent):
        self.parent=parent
        self.data=None #Default value, to say its not been set yet
        self.root=Toplevel(self.parent)
        self.root.transient(self.parent)
        self.username=Entry(self.root)
        self.password=Entry(self.root, show="*")
        self.ok=Button(self.root, text="Continue", command=self.check_pass); self.ok.grid(row=5, column=2, sticky="ew")
        self.cancel=Button(self.root, text="Cancel", command=self.cancel_pass); self.cancel.grid(row=5, column=1, sticky="ew")
        
    def check_pass(self):
        self.data=(self.username.get(), self.password.get())
        self.root.quit()

    def cancel_pass(self):
        self.data=False
        self.root.quit()

parent=Tk()
pass_window=LoginWindow(parent)
#....? how do I get pass_window.data from the window, considering it will only be defined 
#to be something besides None once the user has clicked the continue button

I have tried loops to wait for the value of pass_window.data to change from None, however that leads to LoginWindow not appearing, or the script locking up. Ideally I want to keep transient there as it prevents the user clicking off the window, but I know that transient is the cause of the window not appearing (works fine without)

Any ideas?


Solution

  • You're kinda asking two questions in one, one about passing a value from a popup window to the main window, one about transient not working correctly. My answer to the first question is below, for the second one I don't really know what the problem you're experiencing is. As far as I can see, transient works as intended the way you use it.


    You can use wait_window to let the Tkinter mainloop wait for a window to close before continuing. If you place the popup window creation in a function that is called after the parent's mainloop is started, you can use pass_window.wait_window() to "pause" further execution of the function before continuing with executing rest of the lines. After the window has closed, the desired data can then be found in pass_window.data

    class LoginWindow(object):
        def __init__(self, parent):
            self.parent=parent
            self.data=None #Default value, to say its not been set yet
            self.root=Toplevel(self.parent)
            self.root.transient(self.parent)
            self.username=Entry(self.root); self.username.pack()
            self.password=Entry(self.root, show="*"); self.password.pack()
            self.ok=Button(self.root, text="Continue", command=self.check_pass); self.ok.pack()
            self.cancel=Button(self.root, text="Cancel", command=self.cancel_pass); self.cancel.pack()
    
        def check_pass(self):
            self.data=(self.username.get(), self.password.get())
            self.root.destroy()
    
        def cancel_pass(self):
            self.data=False
            self.root.destroy()
    
    
    def popup():
        pass_window=LoginWindow(parent)
        pass_window.parent.wait_window(pass_window.root)
        print(pass_window.data)
    
    parent=Tk()
    Button(parent, text='popup', command=popup).pack()
    parent.mainloop()