Почему я получаю эту ошибку AttributeError: у объекта 'NoneType' нет атрибута 'remove_widget', когда я пытаюсь удалить целевой виджет? - PullRequest
0 голосов
/ 25 февраля 2019

Почему я получаю эту ошибку 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 голосов
/ 25 февраля 2019

AttributeError

AttributeError: у объекта 'NoneType' нет атрибута 'remove_widget'

Причина

Ошибка AttributeError произошла во второй раз при попыткена remove_widget, потому что экземпляр виджета / цели больше не имеет родителя, и Clock.schedule_interval все еще активен для этого экземпляра виджета / цели.

Примечание

Первый раз, когда self.xменьше 0, экземпляр виджета / цели был успешно удален.

Решение

Вам необходимо отменить планирование событие, используя Clock.unschedule(self.event).

Отрывки

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)
0 голосов
/ 25 февраля 2019

Я имею в виду родительский класс BattleField, не так ли

Нет, не так.Вы ссылаетесь на атрибут «parent» текущего экземпляра «Target», который - из полученной ошибки - очевидно, None на данный момент.Это может быть экземпляром вашего BattleField класса в какой-то момент, но это может быть и что-нибудь еще.

Из документа (выделение мое):

Родитель виджета устанавливается при добавлении виджета к другому виджету и сбрасывается при удалении виджета из родительского элемента .

Так что, скорее всего, происходит то, что 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 и даже меньше, ваше приложение, поэтому я не могу сказать, но вы, возможно, не все делаете правильно, и у вас может быть некоторая утечка памяти здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...