Skip to content
Advertisement

How to update function by milliseconds in Kivy

I’m making a stopwatch using Kivy that includes “Minutes, seconds, milliseconds”.

But the problem is that the Clock method doesn’t seem to support the shorter time below 0.02. So no matter what numbers you give, it still can not catch up with the milliseconds’ change and counting time slower than the real-time (You can see it clearly in my code below).

So is there any better way to update my Kivy’s GUI by milliseconds, so I can display the numbers on my app’s screen?

Here’s the code I extracted from my main source:

from kivy.uix.relativelayout import RelativeLayout

from kivy.lang import Builder

from kivy.clock import Clock

from functools import partial

Builder.load_string("""
<ModifyTime>:
    id: name
    
    BoxLayout:
        id: time
        
        spacing: 1
        
        size_hint_y: None
        height: minute.height
    
        TextInput:
            id: minute
            hint_text: "Minutes"
            
            size_hint: None,None
            width: time_scale.texture_size[0] + dp(14)
            height: time_scale.texture_size[1] + dp(12)
            
            multiline: False
            
        TextInput:
            id: second
            hint_text: "Seconds"
            
            size_hint: None,None
            width: time_scale.texture_size[0] + dp(14)
            height: time_scale.texture_size[1] + dp(12)
            
            multiline: False
            
        TextInput:
            id:milisecond
            hint_text: "Miliseconds"
            
            size_hint: None,None
            width: time_scale.texture_size[0] + dp(14)
            height: time_scale.texture_size[1] + dp(12)
            
            multiline: False
            
        Button:
            text: "Activate stopwatch"
            on_release:
                root.activate_stopwatch(root)
            
    Label:
        id: time_scale
        opacity: 0
        text: "00:00:00"
        
        size_hint: None,None
        size: 0,0
    
""")
    
class ModifyTime(RelativeLayout):
    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        
    def activate_stopwatch(self,watch):
        watch.ids.minute.text="0"
        watch.ids.second.text="0"
        watch.ids.milisecond.text="0"
        self.stopwatch=Clock.schedule_interval(partial(self._time_update,watch),0.001)
        
    def _time_update(self,watch,dt):
        watch.ids.milisecond.text=str(int(watch.ids.milisecond.text)+1)
        
        self._time_update_calculate(watch)

    def _time_update_calculate(self,watch):
        if watch.ids.milisecond.text == "1000":
            watch.ids.milisecond.text = "0"
            watch.ids.second.text=str(int(watch.ids.second.text)+1)
        if watch.ids.second.text == "60":
            watch.ids.second.text == "0"
            watch.ids.minute.text=str(int(watch.ids.minute.text)+1)

if __name__ == "__main__":
    from kivy.app import App
    
    class TestApp(App):
        def build(self):
            return ModifyTime()
    
    TestApp().run()

Advertisement

Answer

I modified your .py code to the following which should fairly count upto milliseconds (should work without any changes in config).

class ModifyTime(RelativeLayout):
    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        self.milisec = 0
        
    def activate_stopwatch(self,watch):
        watch.ids.minute.text="0"
        watch.ids.second.text="0"
        watch.ids.milisecond.text="0"
        self.stopwatch=Clock.schedule_interval(partial(self._time_update,watch),0.001)
        
    def _time_update(self,watch,dt):
        self.milisec += 1000*dt
        sec, mili = divmod(self.milisec, 1000)
        mint, sec = divmod(sec, 60)

        watch.ids.milisecond.text = str(int(mili))
        watch.ids.second.text = str(int(sec))
        watch.ids.minute.text = str(int(mint))


if __name__ == "__main__":
    from kivy.app import App
    
    class TestApp(App):
        def build(self):
            return ModifyTime()
    
    TestApp().run()

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement