Search code examples
pythonkivy

How to schedule the creation of a widget in kivy


I am trying to create a GUI application in kivy where one function that will get activated on a button press schedules the execution of another function at a later time, which creates a new widget.

This is what I am attempting to implement.

main.py

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.clock import Clock
Builder.load_file('test.kv')

class MyLayout(Widget):

    def schedule_widget(self):
        Clock.schedule_once(MyLayout.add_label, 5)

    def add_label(self):
        self.ids.id.add_widget(Label(text=f'Hello World'))

class MyApp(App):
    def build(self):
        return MyLayout()

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

test.kv

<MyLayout>
    BoxLayout:
        orientation: 'horizontal'
        size: root.width, root.height
        id: id
        Button:
            text: 'Add A Label in 5 seconds'
            on_release: app.root.schedule_widget()

It crashes and returns the error AttributeError: 'float' object has no attribute 'ids', when the button is clicked. If I replace the on_release: to directly execute the add_label function, it successfully adds the label even though it is doing the same thing, just without the delay.


Solution

  • You are treating add_label() as a static method, but it is not. The error comes from add_label() expecting its argument to be self, but instead it is getting the dt (delta time) provided by Clock.schedule_once(). Try modifying your MyLayout class as:

    class MyLayout(Widget):
    
        def schedule_widget(self):
            Clock.schedule_once(self.add_label, 5)  # use `self` to access method
    
        def add_label(self, dt):  # add dt argument
            self.ids.layoutId.add_widget(Label(text=f'Hello World'))  # use correct id