You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决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。

修复步骤

  1. 删除错误代码:检查submit函数中是否存在'first': kv.input_box.text,这类语句,直接删除即可。你当前代码里已经写了正确的获取方式:kv.get_screen('second').ids.input_box.text,只要没有遗留错误代码,这一步就能解决报错。

  2. 优化代码健壮性:

    • 避免依赖全局变量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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:05:21