解决Kivy中submit函数调用input_box报AttributeError的问题
问题描述
我正在开发一个简单的测试应用,功能如下:
- 第一屏:显示“hi”,下方有“next”按钮可进入下一页面;
- 第二屏:显示“enter your email address”,下方有文本输入框用于填写邮箱,还有“validate”按钮,点击可将邮箱发送至在线ElephantSQL数据库。
我写了包含submit函数的test.py脚本,负责将邮箱发送到ElephantSQL数据库,完成后显示感谢提示,但运行时出现错误,报错栈如下:
Traceback (most recent call last): File "C:\Users\User\Documents\Pers\Python\test\test.py", line 99, in <module> Yes().run() File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\app.py", line 955, in run runTouchApp() File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 574, in runTouchApp EventLoop.mainloop() File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 339, in mainloop self.idle() File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 383, in idle self.dispatch_input() File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 334, in dispatch_input post_dispatch_input(*pop(0)) File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 302, in post_dispatch_input wid.dispatch('on_touch_up', me) File "kivy\_event.pyx", line 731, in kivy._event.EventDispatcher.dispatch File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\uix\behaviors\button.py", line 179, in on_touch_up self.dispatch('on_release') File "kivy\_event.pyx", line 727, in kivy._event.EventDispatcher.dispatch File "kivy\_event.pyx", line 1307, in kivy._event.EventObservers.dispatch File "kivy\_event.pyx", line 1191, in kivy._event.EventObservers._dispatch File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 55, in custom_callback exec(__kvlang__.co_value, idmap) File "C:\Users\User\Documents\Pers\Python\test\Test.kv", line 77, in <module> on_release: app.submit() File "C:\Users\User\Documents\Pers\Python\test\test.py", line 87, in submit 'first': kv.input_box.text, AttributeError: 'WindowManager' object has no attribute 'input_box'
以下是我的代码文件:
test.py文件
from kivy.app import App from kivy.uix.gridlayout import GridLayoutException from kivy.uix.label import Label from kivy.uix.image import Image from kivy.uix.button import Button from kivy.uix.textinput import TextInput from kivy.uix.widget import Widget from kivy.lang import Builder from kivy.uix.screenmanager import ScreenManager, Screen import os import urllib.parse as up import psycopg2 #define our different windows (hence our different pages in our app) class FirstWindow(Screen): pass class SecondWindow(Screen): pass #define our screen manager (hence what manages the different pages in our app) class WindowManager(ScreenManager): pass # designate our .kv design file kv = Builder.load_file('Test.kv') class Yes(App): def build(self): url = up.urlparse("DBURL") # connect to the database conn = psycopg2.connect("dbname='DBNAME' user='DBUSER' host='DBHOST' password='DBPWD'") # create the database cursor cur = conn.cursor() # insert the query to create the table (if not yet # created) in which the data (email addresses # will be stored) cur.execute("CREATE TABLE if not exists emails(id INTEGER PRIMARY KEY, address text)") # commit changes conn.commit() # close the connection to the database conn.close() return kv # define our submit function, i.e. the function which will be # triggered when we click to send the email address to be # stored in the database def submit(self): # database URL url = up.urlparse("DBURL") # connect to the database conn = psycopg2.connect("dbname='DBNAME' user='DBUSER' host='DBHOST' password='DBPWD'") # create the database cursor cur = conn.cursor() # insert the query to submit the data, # i.e. email addresses to the database psycopg_command = "INSERT INTO emails (address) VALUES (%s)" values = (kv.get_screen('second').ids.input_box.text,) cur.execute(psycopg_command, values) # add message to user once email address has been submitted kv.get_screen('second').ids.input_box.text = "Thanks for submitting your email address" # clear the input box once the email address has been submitted '''kv.get_screen('second').ids.input_box.text = ""''' # commit changes conn.commit() # close the connection to the database conn.close() if __name__ == '__main__': Yes().run()
Test.kv文件
#:import NoTransition kivy.uix.screenmanager.NoTransition WindowManager: FirstWindow: SecondWindow: <FirstWindow>: name: "first" BoxLayout: orientation: "vertical" size: root.width, root.height Label: text: "Hi" font_size: 32 Button: text: "Next" size_hint: 0.3, 0.3 pos_hint: {"center_x":0.5} background_color: 0.06666666666, 0.82352941176, 0.90980392156, 1 background_normal: "" on_release: app.root.current = "second" root.manager.transition.direction = "left" Widget: size_hint: 0.3, None height: 6 canvas: Color: rgb: 0, 0, 0, 1 <SecondWindow>: name: "second" BoxLayout: orientation: "vertical" size: root.width, root.height Label: id: word_label text: "Enter your email address" font_size: 32 Widget: size_hint: 0.3, None height: 6 canvas: Color: rgb: 0, 0, 0, 1 TextInput: id: input_box size_hint: (0.3, 0.2) pos_hint: {"center_x":0.5} multiline: False valign: "center" halign: "center" text:"" Widget: size_hint: 0.3, None height: 6 canvas: Color: rgb: 0, 0, 0, 1 Button: text: "Validate" size_hint: 0.3, 0.3 pos_hint: {"center_x":0.5} background_color: 0.06666666666, 0.82352941176, 0.90980392156, 1 background_normal: "" on_release: app.submit() Widget: size_hint: 0.3, None height: 6 canvas: Color: rgb: 0, 0, 0, 1 Button: text: "Home" size_hint: 0.3, 0.3 pos_hint: {"center_x":0.5} background_color: 0.06666666666, 0.82352941176, 0.90980392156, 1 background_normal: "" on_release: app.root.current = "first" root.manager.transition = NoTransition() Widget: size_hint: 0.3, None height: 6 canvas: Color: rgb: 0, 0, 0, 1
我理解报错提示“WindowManager”对象没有“input_box”属性,但不知道如何解决这个问题,请问该如何修正错误?
解决方案
错误原因
报错指向的kv.input_box.text代码(应该是你修改前的遗留代码),直接尝试从WindowManager对象(即kv)获取input_box控件,但input_box是SecondWindow屏幕的子控件,WindowManager本身不具备这个属性,因此抛出AttributeError。
修复步骤
删除错误代码:检查
submit函数中是否存在'first': kv.input_box.text,这类语句,直接删除即可。你当前代码里已经写了正确的获取方式:kv.get_screen('second').ids.input_box.text,只要没有遗留错误代码,这一步就能解决报错。优化代码健壮性:
- 避免依赖全局变量
kv:在App类中可以通过self.root访问WindowManager,替换所有kv为self.root,代码更可靠:def submit(self): # 替换所有kv为self.root values = (self.root.get_screen('second').ids.input_box.text,) # ... self.root.get_screen('second').ids.input_box.text = "Thanks for submitting your email address" - 修复数据库主键问题:当前创建表的语句没有设置主键自增,插入数据时会报错,修改为自增主键:
cur.execute("CREATE TABLE if not exists emails(id SERIAL PRIMARY KEY, address text)") - 添加异常处理:避免数据库操作失败导致程序崩溃:
def submit(self): try: conn = psycopg2.connect("dbname='DBNAME' user='DBUSER' host='DBHOST' password='DBPWD'") cur = conn.cursor() psycopg_command = "INSERT INTO emails (address) VALUES (%s)" email = self.root.get_screen('second').ids.input_box.text.strip() if not email: self.root.get_screen('second').ids.input_box.text = "Please enter a valid email" return values = (email,) cur.execute(psycopg_command, values) conn.commit() self.root.get_screen('second').ids.input_box.text = "Thanks for submitting your email address" except Exception as e: self.root.get_screen('second').ids.input_box.text = f"Error: {str(e)}" if 'conn' in locals(): conn.rollback() finally: if 'conn' in locals(): conn.close()
- 避免依赖全局变量
完成以上修改后,重新运行程序即可正常提交邮箱到数据库。
内容的提问来源于stack exchange,提问作者Programy
相关产品推荐
相关产品推荐

