Search code examples
pythonkivy

How to remove a kivy child that are made dynamically?


I create a sample kivy script that dynamically adding button to the widget then remove it automatically using clock.schedule_once function. I was able to referred to the widget children to change the button text. However when i try to remove the widget itself, it did not work. Instead it gave me RecursionError. Please help me out on how to remove the widget. I added some comment that causes the error in the script :

from kivy.app import App 
from kivy.clock import Clock 
from kivy.uix.boxlayout import BoxLayout 
from kivy.uix.label import Label 
from kivy.uix.button import Button 
from kivy.properties import ObjectProperty

class nbutton(Button):
    buttonid=ObjectProperty(None)

class MyWidget(BoxLayout):
    childs = []
    def __init__(self,*args):
        Clock.schedule_once(self.add_widgets,1)
        Clock.schedule_once(self.remove_widget,2)

        return super().__init__(*args)

    def add_widgets(self,*args):
        #self.r = BoxLayout(size_hint=(1,1),id="nice")
        #self.add_widget(self.r)
        self.add_widget(Button(text="Hello",id='dasd'))
        self.add_widget(Button(text="World",id='q'))
        self.add_widget(Button(text="nice",id='dz'))
        self.add_widget(Button(text="good",id='m'))

    def remove_widget(self,*args):
        #m = App.get_running_app().root.ids.nice
        
        #self.remove_widget(self.children.ids.dasd)
        #self.clear_widgets()
        #for child in [child for child in self.children if child.text != "Hello"]:
            #self.remove_widget(child)
            #print(child)
        #self.remove_widget(self.child.m)
        for chi in self.children:
            self.childs.append(chi)
            print(chi)
        #print(self.childs.text)
        #try:
        self.childs[2].text = 'hihih'


        #------------------------ this part is broken ------------------------------
        self.remove_widget(self.childs[2])
        #------------------------ this part is broken ------------------------------
        # error message:
        #  RecursionError: maximum recursion depth exceeded while calling a Python object






        # except:
        #   pass
        # for c in childs:
        #   self.remove_widget(c)
        #for child in self.children:
            #self.remove(child)
            #print(child.id)
        #   if child.text == 'Hello':
        #       #print(child)
        #       self.remove_widget(child)
        #pass
class MpApp(App):
    def build(self):
        return MyWidget()

if __name__ == '__main__':
    MpApp().run()```

Solution

  • Within your remove_widget() method, you are recursing into remove_widget() with the call:

    self.remove_widget(self.childs[2])
    

    If you are going to recurse like that, you need some test to end the recursion, otherwise it will recurse infinitely.

    Also, you are redefining the remove_widget() method of MyWidget (which is a BoxLayout) without ever calling the actual remove_widget() method of the superclass (BoxLayout). So the child widget never actually gets removed. Perhaps naming your remove_widget() in MyWidget to something like my_remove_widget() might help.