I've split my tkinter app in more file, and right now I've two file:
main.py
import tkinter as tk
from login_info import LoginInfo
class Main(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.login_page = LoginInfo(self)
self.login_page.pack(expand='True')
if __name__ == "__main__":
root = tk.Tk()
Main(root).pack(side="top", fill="both", expand=True)
root.mainloop()
login_page.py
import tkinter as tk
class LoginInfo(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.login_frame = tk.Frame(self)
self.login_frame.pack()
self.username_label = tk.Label(self.login_frame, text='Username:')
self.username_label.grid(row=0, column=0, padx=(10,0), pady=(10,0))
self.username_entry = tk.Entry(self.login_frame)
self.username_entry.grid(row=0, column=1, padx=(10,0), pady=(10,0))
self.password_label = tk.Label(self.login_frame, text='Password:')
self.password_label.grid(row=1, column=0, padx=(10,0), pady=(10,0))
self.password_entry = tk.Entry(self.login_frame)
self.password_entry.grid(row=1, column=1, padx=(10,0), pady=(10,0))
self.login_button = tk.Button(self.login_frame, text='Login', command=self.login)
self.login_button.grid(row=2, column=0, columnspan=2, pady=20)
root.bind('<Return>', self.login)
def login(self,event):
print('Logged In')
if __name__ == "__main__":
root = tk.Tk()
LoginInfo(root).pack(side="top", fill="both", expand=True)
root.mainloop()
In the login page I'm trying to bind the return button to a function but I'm gettin this error:
NameError: name 'root' is not defined
This happen only if I launch the code from main.py, if I launch it from login_page.py it works
CodePudding user response:
Remove the duplicated ...
if __name__ == "__main__":
root = tk.Tk()
LoginInfo(root).pack(side="top", fill="both", expand=True)
root.mainloop()
... from the login_page.py
and launch the code from main.py
.
Use if __name__ == '__main__':...
only once and only in the module which starts the program. Because only in this module the special variable __main__
will have the value '__main__'
.
Also, make sure that you import from login_page
, not from login_info
in the main.py
, as you named that module login_page.py
and not login_info.py
.
Concrete code
I was able to get your example running by doing this:
# main.py
import tkinter as tk
from login_page import LoginPage
class Main(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.login_page = LoginPage(self)
self.login_page.pack(expand='True')
if __name__ == "__main__":
root = tk.Tk()
main = Main(root)
main.pack(side="top", fill="both", expand=True)
root.mainloop()
# login_page.py
import tkinter as tk
class LoginPage(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.login_frame = tk.Frame(self)
self.login_frame.pack()
self.username_label = tk.Label(self.login_frame, text='Username:')
self.username_label.grid(row=0, column=0, padx=(10,0), pady=(10,0))
self.username_entry = tk.Entry(self.login_frame)
self.username_entry.grid(row=0, column=1, padx=(10,0), pady=(10,0))
self.password_label = tk.Label(self.login_frame, text='Password:')
self.password_label.grid(row=1, column=0, padx=(10,0), pady=(10,0))
self.password_entry = tk.Entry(self.login_frame)
self.password_entry.grid(row=1, column=1, padx=(10,0), pady=(10,0))
self.login_button = tk.Button(self.login_frame, text='Login', command=self.login)
self.login_button.grid(row=2, column=0, columnspan=2, pady=20)
self.bind_all('<Return>', self.login)
def login(self, event=None):
print('Logged In')
The trick is to use self.bind_all
instead of root.bind
, near the bottom of login_page.py
, which binds the key to the whole application. This function seems not to be documented in the official Python tkinter docs, which may indicate that there is a more pythonic solution.
I personally would prefer to put the declaration of this binding in the main.py. We have a sub unit here, which silently modifies a parent unit. The bigger the project gets, the more this leads to problems.