配置 tk 按钮时出现 Tkinter 属性错误
Tkinter Attribute Error when configuring tk Buttons
我正在构建一个 SMTP 邮件发送器,当我开始构建登录 window 时,我在尝试将按钮状态设置为'禁用'。
此示例中的第一个函数是根函数,第二个函数是导致问题的函数。
class smtp_gui(tk.Tk):
is_logged_in = False
user_email = ''
user_passwd = ''
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("SMTP Mail Sender")
self.resizable(False, False)
self.iconbitmap('at.ico')
self.container = tk.Frame(self)
self.btn_container = tk.Frame(self)
self.bind('<Control-s>', self.send)
self.bind('<Control-h>', self.get_help)
self.container.pack(side="top", padx=1, pady=1)
self.container.columnconfigure(1, weight=1)
self.btn_container.pack(side="bottom", padx=1, pady=1, fill='x')
tk.Label(self.container, text='From:').grid(row=0, column=0, sticky='e')
tk.Label(self.container, text='To:').grid(row=1, column=0, sticky='e')
tk.Label(self.container, text='Subject:').grid(row=2, column=0, sticky='e')
self.refresh()
self.To = tk.Entry(self.container)
self.To.grid(row=1, column=1, sticky="we", pady=3, padx=2)
self.Subject = tk.Entry(self.container)
self.Subject.grid(row=2, column=1, sticky="we", pady=2, padx=2)
self.Msg = tk.Text(self.container, width=40, height=5)
self.Msg.grid(columnspan=2, padx=3, pady=3)
send_btn = tk.Button(self.btn_container, text="Send", command=self.send)
send_btn.pack(side='right', padx=2, pady=1)
quit_btn = tk.Button(self.btn_container, text="Quit", command=self.quit)
quit_btn.pack(side='right', padx=2, pady=1)
def send(self, event=None):
print(self.Msg.get("0.0", "end"))
def refresh(self):
if self.logged_in():
try:
self.login_btn.destroy()
except AttributeError:
pass
self.mailabel = tk.Label(self.container, bd=1, text=smtp_gui.user_email, relief='sunken')
self.mailabel.grid(row=0, column=1, pady=3, padx=2, sticky='we')
else:
try:
self.mailabel.destroy()
except AttributeError:
pass
self.login_btn = tk.Button(self.container, text="login before sending", command=self.get_login)
self.login_btn.grid(row=0, column=1, sticky="we", pady=3, padx=2)
def logged_in(self):
return smtp_gui.is_logged_in
def get_login(self):
login = LoginWindow()
self.refresh()
def get_help(self, event=None):
get_help = HelpWindow()
class LoginWindow(tk.Toplevel):
def __init__(self, *args, **kwargs):
# Window config
tk.Toplevel.__init__(self, *args, **kwargs)
self.grab_set()
self.wm_title("Email login")
self.resizable(False, False)
self.iconbitmap('login.ico')
# Containers
self.container = tk.Frame(self)
self.btn_container = tk.Frame(self)
self.container.pack(padx=2, pady=2)
self.btn_container.pack(side="bottom", padx=1, pady=1, fill='x')
# Tracers
self.tracetest = tk.StringVar()
self.tracetest.trace('w', self.tracer)
# Window elements
tk.Label(self.container, text="Gmail address:").grid(row=0, column=0)
tk.Label(self.container, text="Password:").grid(row=1, column=0)
# Entries
self.Address = tk.Entry(self.container, width=44, textvariable=self.tracetest)
self.Address.grid(row=0, column=1, sticky="we", pady=3, padx=2)
self.Address.insert(0, "your address")
self.Passwd = tk.Entry(self.container, show="*", textvariable=None)
self.Passwd.grid(row=1, column=1, sticky="we", pady=3, padx=2)
# Buttons
self.login_btn = tk.Button(self.btn_container, text="Login", command=self.get_credentials)
self.login_btn.pack(side='right', padx=2, pady=3)
storno_btn = tk.Button(self.btn_container, text="Storno", command=self.destroy)
storno_btn.pack(side='right', padx=2, pady=3)
def get_credentials(self):
user_address = self.Address.get()
try:
assert(match(r'[a-zA-Z0-9]+@gmail.com', user_address))
except AssertionError:
messagebox.showwarning("Invalid login", "This is not a valid gmail address!")
def tracer(self, *args):
address = match(r'[a-zA-Z0-9]+@gmail.com', self.Address.get())
passwd = ''
if passwd and address:
self.login_btn.config(state='enabled') # Attribute error here, the program says these buttons don't exist in the functions even tough I defined them above
else:
self.login_btn.config(state='disabled')
有问题的函数在最后(在跟踪器函数中),您应该能够使用此代码重现该问题(只需将 tkinter 导入为 tk 和正则表达式)
我猜这是某种参考问题。
编辑 - 完整追溯
Traceback (most recent call last):
File "C:\Users\david\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1550, in __call__
return self.func(*args)
File "C:\Users\david\Documents\Git_repositories\smtp_client\main_menu.py", line 129, in tracer
self.login_btn.config(state='disabled')
AttributeError: 'LoginWindow' object has no attribute 'login_btn'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\david\Documents\Git_repositories\smtp_client\main_menu.py", line 160, in <module>
root.mainloop()
File "C:\Users\david\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1131, in mainloop
self.tk.mainloop(n)
File "C:\Users\david\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1554, in __call__
self.widget._report_exception()
AttributeError: 'StringVar' object has no attribute '_report_exception'
找到解决方案
发生回溯是因为在创建按钮之前调用了跟踪器,当我在按钮启动后移动跟踪器时,它完美地工作,谢谢你们!
跟踪在值更改时触发。当您执行 self.address.insert(0, "your address")
时值会更改,因为该小部件与变量相关联。所有这些都发生在您定义 self.login_btn
.
之前
您需要在启用跟踪之前或更改跟踪变量的值之前定义按钮。
我正在构建一个 SMTP 邮件发送器,当我开始构建登录 window 时,我在尝试将按钮状态设置为'禁用'。
此示例中的第一个函数是根函数,第二个函数是导致问题的函数。
class smtp_gui(tk.Tk):
is_logged_in = False
user_email = ''
user_passwd = ''
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("SMTP Mail Sender")
self.resizable(False, False)
self.iconbitmap('at.ico')
self.container = tk.Frame(self)
self.btn_container = tk.Frame(self)
self.bind('<Control-s>', self.send)
self.bind('<Control-h>', self.get_help)
self.container.pack(side="top", padx=1, pady=1)
self.container.columnconfigure(1, weight=1)
self.btn_container.pack(side="bottom", padx=1, pady=1, fill='x')
tk.Label(self.container, text='From:').grid(row=0, column=0, sticky='e')
tk.Label(self.container, text='To:').grid(row=1, column=0, sticky='e')
tk.Label(self.container, text='Subject:').grid(row=2, column=0, sticky='e')
self.refresh()
self.To = tk.Entry(self.container)
self.To.grid(row=1, column=1, sticky="we", pady=3, padx=2)
self.Subject = tk.Entry(self.container)
self.Subject.grid(row=2, column=1, sticky="we", pady=2, padx=2)
self.Msg = tk.Text(self.container, width=40, height=5)
self.Msg.grid(columnspan=2, padx=3, pady=3)
send_btn = tk.Button(self.btn_container, text="Send", command=self.send)
send_btn.pack(side='right', padx=2, pady=1)
quit_btn = tk.Button(self.btn_container, text="Quit", command=self.quit)
quit_btn.pack(side='right', padx=2, pady=1)
def send(self, event=None):
print(self.Msg.get("0.0", "end"))
def refresh(self):
if self.logged_in():
try:
self.login_btn.destroy()
except AttributeError:
pass
self.mailabel = tk.Label(self.container, bd=1, text=smtp_gui.user_email, relief='sunken')
self.mailabel.grid(row=0, column=1, pady=3, padx=2, sticky='we')
else:
try:
self.mailabel.destroy()
except AttributeError:
pass
self.login_btn = tk.Button(self.container, text="login before sending", command=self.get_login)
self.login_btn.grid(row=0, column=1, sticky="we", pady=3, padx=2)
def logged_in(self):
return smtp_gui.is_logged_in
def get_login(self):
login = LoginWindow()
self.refresh()
def get_help(self, event=None):
get_help = HelpWindow()
class LoginWindow(tk.Toplevel):
def __init__(self, *args, **kwargs):
# Window config
tk.Toplevel.__init__(self, *args, **kwargs)
self.grab_set()
self.wm_title("Email login")
self.resizable(False, False)
self.iconbitmap('login.ico')
# Containers
self.container = tk.Frame(self)
self.btn_container = tk.Frame(self)
self.container.pack(padx=2, pady=2)
self.btn_container.pack(side="bottom", padx=1, pady=1, fill='x')
# Tracers
self.tracetest = tk.StringVar()
self.tracetest.trace('w', self.tracer)
# Window elements
tk.Label(self.container, text="Gmail address:").grid(row=0, column=0)
tk.Label(self.container, text="Password:").grid(row=1, column=0)
# Entries
self.Address = tk.Entry(self.container, width=44, textvariable=self.tracetest)
self.Address.grid(row=0, column=1, sticky="we", pady=3, padx=2)
self.Address.insert(0, "your address")
self.Passwd = tk.Entry(self.container, show="*", textvariable=None)
self.Passwd.grid(row=1, column=1, sticky="we", pady=3, padx=2)
# Buttons
self.login_btn = tk.Button(self.btn_container, text="Login", command=self.get_credentials)
self.login_btn.pack(side='right', padx=2, pady=3)
storno_btn = tk.Button(self.btn_container, text="Storno", command=self.destroy)
storno_btn.pack(side='right', padx=2, pady=3)
def get_credentials(self):
user_address = self.Address.get()
try:
assert(match(r'[a-zA-Z0-9]+@gmail.com', user_address))
except AssertionError:
messagebox.showwarning("Invalid login", "This is not a valid gmail address!")
def tracer(self, *args):
address = match(r'[a-zA-Z0-9]+@gmail.com', self.Address.get())
passwd = ''
if passwd and address:
self.login_btn.config(state='enabled') # Attribute error here, the program says these buttons don't exist in the functions even tough I defined them above
else:
self.login_btn.config(state='disabled')
有问题的函数在最后(在跟踪器函数中),您应该能够使用此代码重现该问题(只需将 tkinter 导入为 tk 和正则表达式)
我猜这是某种参考问题。
编辑 - 完整追溯
Traceback (most recent call last):
File "C:\Users\david\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1550, in __call__
return self.func(*args)
File "C:\Users\david\Documents\Git_repositories\smtp_client\main_menu.py", line 129, in tracer
self.login_btn.config(state='disabled')
AttributeError: 'LoginWindow' object has no attribute 'login_btn'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\david\Documents\Git_repositories\smtp_client\main_menu.py", line 160, in <module>
root.mainloop()
File "C:\Users\david\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1131, in mainloop
self.tk.mainloop(n)
File "C:\Users\david\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1554, in __call__
self.widget._report_exception()
AttributeError: 'StringVar' object has no attribute '_report_exception'
找到解决方案
发生回溯是因为在创建按钮之前调用了跟踪器,当我在按钮启动后移动跟踪器时,它完美地工作,谢谢你们!
跟踪在值更改时触发。当您执行 self.address.insert(0, "your address")
时值会更改,因为该小部件与变量相关联。所有这些都发生在您定义 self.login_btn
.
您需要在启用跟踪之前或更改跟踪变量的值之前定义按钮。