Search code examples
python-3.xkivykivy-language

Update reusable Label widget in Kivy using Clock.Interval


I'm developing a multiple page Kivy app that I want to have a clock widget in several pages. I was able to implement it on every page as an individual instance but i wanted to change it to a reusable widget but it's not updating during the intervals

This is the .kv file implementation

ScreenManager:
id: screen_manager
HomeScreen:
    id: home_screen
    name: 'home_screen'
    manager: 'screen_manager'

<ClockWidget>:
    Label:
        text_size: self.size
        halign: 'left'
        valign: 'middle'
        id: clocktime
        text: root.ClockTimeDisplay

<HomeScreen>:
    orientation: 'vertical'
    ScrollView:
        do_scroll_x: True
        scroll_distance: 20
        BoxLayout:
            orientation: 'vertical'
            ClockWidget:

here is the .py file. Within the update_clock function I've tried all 3 of these implementations at one time or another. It prints the time properly but doesn't update the label, stays saying "dummy text".

class ClockWidget(Label):
    ClockTimeDisplay = StringProperty()
    ClockTimeDisplay = "dummy text"
    text = ClockTimeDisplay

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

    def update_clock(self, *args):
        print(self.text)
        #I've tried all 3 of these implimentations at one time or another.
        self.ClockTimeDisplay = str(datetime.now().strftime('%H:%M:%S'))
        self.text = str(datetime.now().strftime('%H:%M:%S'))
        self.ids.clocktime.text = str(datetime.now().strftime('%H:%M:%S'))

        return ClockTimeDisplay


class HomeScreen(Screen):
    pass


class regatta_racer(App):
    def build(self):
        clock_widget = ClockWidget()
        Clock.schedule_interval(clock_widget.update_clock, .1)
        return Builder.load_file('regatta_racer.kv')


if __name__ == "__main__":
    regatta_racer().run()

I've also tried triggering the interval within a on_load function inside the ClockWidget but that didn't work either.

Any help would be greatly appreciated.


Solution

  • The problem is that the ClockWidget created in the build method is different from the ClockWidget created as a child of BoxLayout in the .kv, in your case only the Clock only calls the update_clock method of the first.

    On the other hand I see it unnecessary to create a new StringProperty in ClockWidget since it is a Label and has the property "text", and another strange thing is that a Label has another Label as a child.

    Considering the above, the solution is:

    from datetime import datetime
    
    from kivy.app import App
    
    from kivy.clock import Clock
    from kivy.lang import Builder
    
    from kivy.uix.screenmanager import Screen
    from kivy.uix.label import Label
    
    
    class ClockWidget(Label):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            Clock.schedule_interval(self.update_clock, 0.1)
    
        def update_clock(self, *args):
            self.text = datetime.now().strftime("%H:%M:%S")
    
    
    class HomeScreen(Screen):
        pass
    
    
    class regatta_racer(App):
        def build(self):
            return Builder.load_file("regatta_racer.kv")
    
    
    if __name__ == "__main__":
        regatta_racer().run()
    
    ScreenManager:
        id: screen_manager
        HomeScreen:
            id: home_screen
            name: 'home_screen'
            manager: 'screen_manager'
    
    <ClockWidget>:
        text_size: self.size
        halign: 'left'
        valign: 'middle'
    
    <HomeScreen>:
        orientation: 'vertical'
        ScrollView:
            do_scroll_x: True
            scroll_distance: 20
            BoxLayout:
                orientation: 'vertical'
                ClockWidget: