首页 > 解决方案 > 无法从 kivy 文件访问特定 id 到我的 python 错误“AttributeError:'super' object has no attribute '__getattr__'”

问题描述

主要代码 <main.py>

import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.uix.behaviors import ButtonBehavior

class Background(Widget):
    cloud_texture = ObjectProperty(None)
    tree1_texture = ObjectProperty(None)
    tree2_texture = ObjectProperty(None)
    grass_texture = ObjectProperty(None)
    bush_texture = ObjectProperty(None)

    def __init__(self,**kwargs):
        super().__init__(**kwargs)

        self.cloud_texture = Image(source="cloud.png").texture
        self.cloud_texture.wrap = 'repeat'
        self.cloud_texture.uvsize = (Window.width/ self.cloud_texture.width, -1)

        self.tree1_texture = Image(source="tree_1.png").texture
        self.tree1_texture.wrap = 'repeat'
        self.tree1_texture.uvsize = (Window.width/ self.tree1_texture.width, -1)

        self.tree2_texture = Image(source="tree_2.png").texture
        self.tree2_texture.wrap = 'repeat'
        self.tree2_texture.uvsize = (Window.width/ self.tree2_texture.width, -1)

        self.grass_texture = Image(source="grass.png").texture
        self.grass_texture.wrap = 'repeat'
        self.grass_texture.uvsize = (Window.width/ self.grass_texture.width, -1)

        self.bush_texture = Image(source="bush.png").texture
        self.bush_texture.wrap = 'repeat'
        self.bush_texture.uvsize = (Window.width/ self.bush_texture.width, -1)

    def on_size(self, *args):
        self.cloud_texture.uvsize = (self.width / self.cloud_texture.width, -1)
        self.tree1_texture.uvsize = (self.width / self.tree1_texture.width, -1)
        self.tree2_texture.uvsize = (self.width / self.tree2_texture.width, -1)
        self.grass_texture.uvsize = (self.width / self.grass_texture.width, -1)
        self.bush_texture.uvsize = (self.width / self.grass_texture.width, -1)

    def scroll_textures(self, time_passed):
        self.cloud_texture.uvpos = ((self.cloud_texture.uvpos[0] + time_passed/8.0)% Window.width , self.cloud_texture.uvpos[1])
        self.tree1_texture.uvpos = ((self.tree1_texture.uvpos[0] + time_passed/2.0)% Window.width , self.tree1_texture.uvpos[1])
        self.tree2_texture.uvpos = ((self.tree2_texture.uvpos[0] + time_passed/2.0)% Window.width , self.tree2_texture.uvpos[1])
        self.grass_texture.uvpos = ((self.grass_texture.uvpos[0] + time_passed/8.0)% Window.width , self.grass_texture.uvpos[1])
        self.bush_texture.uvpos = ((self.bush_texture.uvpos[0] + time_passed/8.0)% Window.width , self.bush_texture.uvpos[1])

        texture = self.property('cloud_texture')
        texture.dispatch(self)

        texture = self.property('tree1_texture')
        texture.dispatch(self)

        texture = self.property('tree2_texture')
        texture.dispatch(self)

        texture = self.property('grass_texture')
        texture.dispatch(self)

        texture = self.property('bush_texture')
        texture.dispatch(self)

        print("scroll")

    pass

    def on_stop(self):
        pass

class StartWindow(Screen):
    def __init__(self, **kwargs):
        super(StartWindow,self).__init__(**kwargs)
    pass

class GameWindow(Screen):
    def __init__(self, **kwargs):
        super(GameWindow,self).__init__(**kwargs)
    pass

class OptionsWindow(Screen):
    def __init__(self, **kwargs):
        super(OptionsWindow,self).__init__(**kwargs)
    pass

class WindowManager(ScreenManager):
    pass

class MainApp(App):
    

    def __getattr__(self, attr):
        return super().__getattr__(attr)

    def on_start(self):
        Clock.schedule_interval(self.root.ids.background.scroll_textures,1/60.)
        pass


MainApp().run()

“Clock.schedule_interval(g.ids.background.scroll_textures,1/60.)”行不工作。我不了解从 kv 文件调用 id 的基本方法。

main.kv 文件

 WindowManager:
    StartWindow:
    GameWindow:
    OptionsWindow:

<StartWindow>:
    name: "start"
    id: startwindow
    FloatLayout:
        cols:4
        Image:
            source: 'Flying_whale.png'
            allow_stretch: True
            keep_ratio: False
        Button:
            pos_hint:{"x":0,"y":0.50}
            background_color: 0,0,0,0
            color: 0,0,0,1
            size_hint: 0.4, 0.1
            font_size: (root.width**2 + root.height**2) / 17**3.3
            text: "Start!"
            id: set_event
            on_press:
                root.manager.transition.direction = "down"
                root.on_start()
        Button:
            pos_hint:{"x":0.15,"y":0.25}
            background_color: 0,0,0,0
            color: 0,0,0,1
            size_hint: 0.4, 0.1
            font_size: (root.width**2 + root.height**2) / 17**3.5
            text: "Options"
            on_release:
                root.manager.transition.direction = "right"
                app.root.current = "options"
        Button:
            pos_hint:{"x":0.15,"y":0.10}
            background_color: 0,0,0,0
            color: 0,0,0,1
            size_hint: 0.4, 0.1
            font_size: (root.width**2 + root.height**2) / 17**3.5
            text: "Exit"
<GameWindow>
    name:"game"
    id: gamewindow
    FloatLayout:
        Background:
            id: background
            canvas.before:
                Rectangle:
                    size: self.size
                    pos: self.pos
                    source: "sky.png"
                Rectangle:
                    size: self.width, 150
                    pos: self.pos[0],self.pos[1] + self.height - 138
                    texture: self.cloud_texture
                Rectangle:
                    size: self.width, 160
                    pos: self.pos[0],self.pos[1]
                    texture: self.grass_texture
                Rectangle:
                    size: self.width, 100
                    pos: self.pos[0]-10,self.pos[1] + 145
                    texture: self.tree1_texture
                Rectangle:
                    size: self.width, 100
                    pos: self.pos[0]+30,self.pos[1] + 160
                    texture: self.tree2_texture
                Rectangle:
                    size: self.width, 20
                    pos: self.pos[0],self.pos[1] + 155
                    texture: self.bush_texture
            Label:
                id: score
                size_hint_y : None
                height : 96
                text: "0"
                font_size: 40

            Button:
                pos_hint:{"x":0,"y":0.25}
                background_color: 0,0,0,0
                color: 0,0,0,1
                size_hint: 0.4, 0.1
                font_size: (root.width**2 + root.height**2) / 17**3.3
                text: "Back"
                id: set_event
                on_release:
<OptionsWindow>:
    name: "options"
    FloatLayout:
        cols:4
        Image:
            source: 'Flying_whale.png'
            allow_stretch: True
            keep_ratio: False
        Button:
            pos_hint:{"x":0.15,"y":0.20}
            background_color: 0,0,0,0
            color: 0,0,0,1
            size_hint: 0.4, 0.1
            font_size: (root.width**2 + root.height**2) / 17**3.5
            text: "Back"
            on_release:
                root.manager.transition.direction = "left"
                app.root.current = "start"
        Button:
            pos_hint:{"x":0.15,"y":0.35}
            background_color: 0,0,0,0
            color: 1,1,1,1
            size_hint: 0.4, 0.1
            font_size: (root.width**2 + root.height**2) / 17**3.5
            text: "Mode : Night / Day"

错误由下式给出:

AttributeError:“超级”对象没有属性“ getattr

我知道这是一个简单的理解问题,但我无法解决它。谢谢

标签: pythonkivykivy-language

解决方案


问题是是在规则中id: background定义的。根据文档GameWindowkv

当处理 kv 文件时,所有带有 id 标记的小部件的弱引用被添加到根小部件的 ids 字典中。

虽然该术语root widget被过度使用并且根据上下文具有不同的含义,但这里它的意思rule是包含id. 所以background id只会出现在idsGamWindow部件的。

知道了这一点,您有问题的代码行可以替换为:

Clock.schedule_interval(self.root.get_screen('game').ids.background.scroll_textures,1/60.)

上面的代码用于get_screen()访问GameWindow.


推荐阅读