为什么“widget”没有删除“Target”属性的widget?

2024-06-11 04:04:12 发布

您现在位置:Python中文网/ 问答频道 /正文

当我试图删除目标widget时,为什么我得到这个错误AttributeError:“NoneType”对象没有属性“remove\u 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()

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

^{pr2}$

请帮帮我。高级谢谢。在


Tags: fromcoreimportselfconfigtargetinitdef
2条回答

属性错误

AttributeError: 'NoneType' object has no attribute '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)

I'm referring to the parent class BattleField, isn't it

不,不是的。您引用的是当前“Target”实例的“parent”属性,从您得到的错误来看,这个属性显然是None。在某个时刻,它可能是您的BattleField类的一个实例,但也可能是其他任何类型的实例。在

From the doc(重点是我的):

The parent of a widget is set when the widget is added to another widget and unset when the widget is removed from its parent.

所以最有可能发生的是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,更不知道你的应用程序,所以我不能告诉你,但你可能做得不对,你可能有一些内存泄漏。在

相关问题 更多 >