Python 属性错误:';超级';对象没有属性'__getattr';在Kivy中将BoxLayout与多个kv文件一起使用时出错

Python 属性错误:';超级';对象没有属性'__getattr';在Kivy中将BoxLayout与多个kv文件一起使用时出错,python,kivy,kivy-language,Python,Kivy,Kivy Language,我很清楚,这个问题已经被问了好几次了。但在尝试了以下解决方案之后: 我已经得出结论,我需要帮助解决我的具体问题。列出的解决方案在我的具体案例中似乎不起作用 以下情况: 我目前正在尝试使用kivy为智能手机开发一个应用程序。因为我喜欢我的代码非常干净和清晰的结构,所以我将我的Kivy代码分割成几个kv文件。python代码应该主要包含逻辑,仅此而已。为了让它正常工作,我需要引用不同kv文件中不同对象的实例。为了澄清我的问题,我构建了一个相当简单的示例: 文件:trument.py fr

我很清楚,这个问题已经被问了好几次了。但在尝试了以下解决方案之后:

我已经得出结论,我需要帮助解决我的具体问题。列出的解决方案在我的具体案例中似乎不起作用

以下情况:

我目前正在尝试使用kivy为智能手机开发一个应用程序。因为我喜欢我的代码非常干净和清晰的结构,所以我将我的Kivy代码分割成几个kv文件。python代码应该主要包含逻辑,仅此而已。为了让它正常工作,我需要引用不同kv文件中不同对象的实例。为了澄清我的问题,我构建了一个相当简单的示例:

文件:trument.py

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.factory import Factory
from kivy.uix.label import Label
from kivy.lang import Builder

x= 1

class ComplexBox(Widget):
    def testit(self):
        self.ids.layout.add_widget(Label(text = "Requirement A met."))
    def addsome(self):
        global x
        self.ids.layout.add_widget(SomeWidget(id="XXX"+str(x)))
        x = x +1
    pass

class SomeWidget(Widget):
    def change(self):
        self.ids.REQB.text = "Requirement B met."
    pass

class RequirementC(Widget):
    def triggerC(self):
        self.ids.ERRORBUTTON.text = "Requirement C met"
    pass

class Attempt(App):
    def build(self):
        return presentation
    pass


presentation = Builder.load_file("attempt.kv")
Attempt().run()
文件:trument.kv

#:kivy 1.0
#:include attemptsupp.kv
#:include attemptsuppC.kv

# root
<ComplexBox>:
    BoxLayout:
        id: layout
        size: root.size
        Button:
            id: ERRORBUTTON
            text: "add"
            on_press: root.addsome()
            on_release: root.testit()
BoxLayout:
    orientation: 'vertical'
    ComplexBox:
    RequirementC:
:kivy 1.0
#:包括额定电压
#:包括C.kv
#根
:
盒子布局:
id:布局
大小:root.size
按钮:
id:ERRORBUTTON
正文:“添加”
按:root.addsome()
发布时:root.testit()
盒子布局:
方向:“垂直”
ComplexBox:
要求C:
文件:attemptupp.kv

#:kivy 1.0

# rules for the widget
<SomeWidget>:
    BoxLayout:
        pos: root.pos
        size: root.size
        orientation: "vertical"
        Label:
            id: REQB
            text: "hello"
        Button:
            text: "world"
            on_release: root.change()
:kivy 1.0
#小部件的规则
:
盒子布局:
pos:root.pos
大小:root.size
方向:“垂直”
标签:
id:REQB
文字:“你好”
按钮:
案文:“世界”
发布时:root.change()
文件:attemptuppc.kv

#:kivy 1.0

<RequirementC>:
    Button:
        id: REQC
        text: "Press"
        on_release: root.triggerC()
:kivy 1.0
:
按钮:
id:REQC
正文:“新闻”
发布时:root.triggerC()

在kivy版本1.10和Python版本3.7.2下运行时,程序首先启动得非常好。但当我按下标有id ERRORBUTTON的“press”(按下)按钮时,我得到以下错误:

...--default --nodebug --client --host localhost --port 57777...\attempt.py "
[INFO   ] [Logger      ] Record log in...\.kivy\logs\kivy_19-03-15_31.txt
[INFO   ] [Kivy        ] v1.10.1
[INFO   ] [Python      ] v3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 
...
[INFO   ] [Window      ] auto add sdl2 input provider
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
[WARNING] [Lang        ] attemptsupp.kv has already been included!
[WARNING] [Lang        ] attemptsuppC.kv has already been included!
[INFO   ] [Base        ] Start application main loop
[INFO   ] [GL          ] NPOT texture support is available
[INFO   ] [Base        ] Leaving application in progress...
 Traceback (most recent call last):
   File "kivy\properties.pyx", line 838, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'ERRORBUTTON'

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "...\ptvsd_launcher.py", line 45, in <module>
     main(ptvsdArgs)
   ...
   File "e:\Daten\Github_Projects\pc-clicker\attempt.py", line 35, in <module>
     Attempt().run()
   File "...\lib\site-packages\kivy\app.py", line 826, in run
     runTouchApp()
...
   File ...\lib\site-packages\kivy\lang\builder.py", line 64, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File ...\attemptsuppC.kv", line 7, in <module>
     on_release: root.triggerC()
   File "...\attempt.py", line 25, in triggerC
     self.ids.ERRORBUTTON.text = "Requirement C met"
   File "kivy\properties.pyx", line 841, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'
…--default--nodebug--client--host localhost--port 57777…\trument.py”
[信息][记录器]记录登录…\.kivy\logs\kivy\u 19-03-15\u 31.txt
[INFO][Kivy]v1.10.1
[INFO][Python]v3.7.2(tags/v3.7.2:9A3FFC0492192018年12月23日,
...
[信息][窗口]自动添加sdl2输入提供程序
[信息][窗口]不允许使用虚拟键盘,单模,未对接
[警告][Lang]attemptupp.kv已包含在内!
[警告][Lang]attemptuppc.kv已包含在内!
[INFO][Base]启动应用程序主循环
[INFO][GL]提供NPOT纹理支持
[INFO][Base]正在退出应用程序。。。
回溯(最近一次呼叫最后一次):
文件“kivy\properties.pyx”,第838行,位于kivy.properties.observedict.\uu getattr__
KeyError:“ERRORBUTTON”
在处理上述异常期间,发生了另一个异常:
回溯(最近一次呼叫最后一次):
文件“…\ptvsd_launcher.py”,第45行,在
干管(ptvsdArgs)
...
文件“e:\Daten\Github\u Projects\pc clicker\trust.py”,第35行,在
尝试().run()
文件“…\lib\site packages\kivy\app.py”,第826行,正在运行
runTouchApp()
...
文件…\lib\site packages\kivy\lang\builder.py”,第64行,在自定义\u回调中
exec(\uuuukVLANG\uuuuuuu.co\u值,idmap)
文件…\attemptuppc.kv”,第7行,在
发布时:root.triggerC()
triggerC中第25行的文件“…\trument.py”
self.ids.ERRORBUTTON.text=“满足要求C”
文件“kivy\properties.pyx”,第841行,位于kivy.properties.observedict.\uu getattr__
AttributeError:“super”对象没有属性“\uuu getattr\uuuu”
尽管我缩短了错误消息,但应该很清楚发生了什么。我在RequirementC类中引用的ERRORBUTTON id在字典中找不到。现在来回答我的问题:

我怎样才能让它工作?我缺少什么

简而言之,我试过几件事:

  • 我尝试过在屏幕中包装BoxLayouts并通过screenmanager访问它们
  • 我尝试在python代码中重新排列顺序(例如,首先加载主kv文件)
  • 我尝试过使用Builder工厂并在那里注册不同的类
  • 我已尝试更改引用。(例如self.ids。['ERRORBUTTON']…)
在我的情况下,这些尝试似乎都不起作用

总而言之:


我如何让我的kivy引用在不同的类中正常工作,为什么ERRORBUTTON id不在我正在查看的dict中?

问题是由常见错误引起的,id与小部件有关,例如,在您的情况下,让我们分析表达式:

self.ids.ERRORBUTTON
谁是self?self是RequirementC的实例

您有什么实例?然后让我们看看.kv在哪里实现了RequirementC:

<RequirementC>:
    Button:
        id: REQC
        text: "Press"
        on_release: root.triggerC()
尝试.kv

#:kivy 1.0
#:include attemptsupp.kv
#:include attemptsuppC.kv

# root
<ComplexBox>:
    error_button: ERRORBUTTON # <---
    BoxLayout:
        id: layout
        size: root.size
        Button:
            id: ERRORBUTTON
            text: "add"
            on_press: root.addsome()
            on_release: root.testit()
BoxLayout:
    orientation: 'vertical'
    ComplexBox:
        id: complex_box
    RequirementC:
        on_release: complex_box.error_button.text = "Requirement C met"
#:kivy 1.0

<RequirementC>:
    Button:
        id: REQC
        text: "Press"
        on_release: root.dispatch('on_release')
:kivy 1.0
#:包括额定电压
#:包括C.kv
#根
:

error_button:ERRORBUTTON#因此,经过一点研究,我找到了我想要的答案。对于那些可能也会被我的问题绊倒的人,这里有:

class RequirementC(Widget):
def triggerC(self):
    presentation.children[1].ids.ERRORBUTTON.text = "Requirement C met"
pass
通过查看演示文稿的子项,可以使用“ids”方法


但是对于那些现在想使用它的人,我建议迭代子对象以找到正确的id,而不是给出一个“硬”引用(子对象[1]).

谢谢你的快速回答。在我的例子中,我的应用程序可能连接到数据库。这就是为什么我需要从python代码中按id访问按钮和标签。我希望能够动态添加新的小部件,给它们一个id,然后用python程序的不同方式操作它们。kv文件应该是我在不同的地方插入了或多或少的空模板。如果我理解正确,在kv文件中对发布操作进行了硬编码。有没有办法避免这种情况
#:kivy 1.0

<RequirementC>:
    Button:
        id: REQC
        text: "Press"
        on_release: root.dispatch('on_release')
class RequirementC(Widget):
def triggerC(self):
    presentation.children[1].ids.ERRORBUTTON.text = "Requirement C met"
pass