当我尝试删除目标小部件时,为什么会收到此错误AttributeError:'NoneType'对象没有属性'remove_widget'?

时间:2019-02-25 09:29:16

标签: python kivy

为什么我会收到此错误AttributeError:当我尝试删除“目标”小部件时,“ NoneType”对象没有属性“ remove_widget”?

from kivy.config import Config
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '600')
from kivy.app import App
from kivy.clock import Clock
from kivy.core.text import LabelBase
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Rectangle
from kivy.lang import Builder
from kivy.config import Config
import random, time

from kivy.animation import Animation

from kivy.properties import ListProperty
from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty

from kivy.core.window import Window

import random



a = Builder.load_string('''

<BattleField>:
    BoxLayout:
        orientation: 'vertical'


<Target>:
    canvas:
        Color:
            rgba: 1, 0, 0, 1 #red
        Rectangle:
            pos: self.pos
            size: self.size
''')


class BattleField(Widget):

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

        appear_time = random.randint(2,4)
        Clock.schedule_interval(self.appear_target, 1)


    def appear_target(self, *args):

        c = Target(pos=(700,0))
        self.add_widget(c)


class Target(Widget):

    velocity_x = NumericProperty(-10)
    velocity_y = NumericProperty(0)

    def __init__(self, **kwargs):
        super(Target, self).__init__(**kwargs)
        Clock.schedule_interval(self.update, 1/60.)

    def update(self, *args):

        self.x += self.velocity_x #velocity[0]
        self.y += self.velocity_y #velocity[1]


        if self.x < 0:
            self.parent.remove_widget(self)



class ClockApp(App):

    def build(self):
        return BattleField()


if __name__ == '__main__':
    ClockApp().run()

我想删除目标小部件,它是一个红色矩形 当它移出窗口时,但这部分会导致错误 我不知道为什么。

if self.x < 0:
   self.parent.remove_widget(self)

请帮助我。谢谢。

2 个答案:

答案 0 :(得分:0)

  

我指的是父类BattleField,不是

不,不是。您所指的是当前“目标”实例的“父”属性,由于您收到的错误,此属性目前显然为None。在某些情况下,它可能是您的BattleField类的一个实例,但是也可以是其他任何东西。

From the doc(强调是我的):

  

在将小部件添加到另一个小部件中时设置小部件的父级,而在从其父级中删除小部件时取消设置。

所以最有可能发生的是,在Target.update()的首次调用之后,self.parent.remove_widget()仍被称为。因此,在这一点上它不再有父级了。您可以轻松对其进行测试:

    if self.x < 0:
        if self.parent:
            # would be better to use the `logging` module
            print("removing target {} from parent {}".format(self, self.parent))
            self.parent.remove_widget(self)
        else:
            print("target {} already removed from parent ?".format(self)) 

但是请注意,Target.update仍在被调用这一事实可能表明您的代码还有其他问题……我不知道kivi,甚至您的应用程序也更少,所以我无法分辨,但您可能无法以正确的方式执行操作,并且此处可能存在内存泄漏。

答案 1 :(得分:0)

AttributeError

  

AttributeError:“ NoneType”对象没有属性“ remove_widget”

原因

第二次尝试remove_widget时发生AttributeError,因为窗口小部件/目标实例不再具有父级,并且Clock.schedule_interval对于该窗口小部件/目标实例仍处于活动状态。

注意

self.x小于0时,第一次成功删除了部件/目标实例。

解决方案

您需要使用Clock.unschedule(self.event) unschedule来活动。

摘要

class Target(Widget):
    velocity_x = NumericProperty(-10)
    velocity_y = NumericProperty(0)

    def __init__(self, **kwargs):
        super(Target, self).__init__(**kwargs)
        self.event = Clock.schedule_interval(self.update, 1 / 60.)

    def update(self, *args):
        self.x += self.velocity_x  # velocity[0]
        self.y += self.velocity_y  # velocity[1]

        if self.x < 0:
            Clock.unschedule(self.event)
            self.parent.remove_widget(self)