0

I have made a simple timer program and a box layout with a label and a button in Kivy. Whenever the button is pressed, I want the timer to start and the label to display the time passed. I followed this tutorial: https://www.youtube.com/watch?v=cggCobcS3vU and then added some of my own stuff to the code, but the label only displays the initial text set in the .kv file. Any fix?

timer.py

import time
from kivy.app import App
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import StringProperty, ObjectProperty




class MyApp(BoxLayout):
    def __init__(self, **kwargs):
        super(MyApp, self).__init__(**kwargs)
        self.output = ''
    def update_label(self):
        self.lbl1.text = str(self.output)
    def count(self, *varargs):

        timeLoop = True

        Sec = 0
        Min = 0
        Hrs = 0


        while timeLoop == True:
            self.update_label()
            print(str(self.output))
            Sec += 1
            time.sleep(1)
            if Sec == 60:
                Sec = 0
                Min += 1
            if Min == 60:
                Min = 0
                Hrs += 1
            if Sec <= 9 and Min <=9 and Hrs <= 9:
                self.output = '0' + str(Hrs) +'.'+ '0' + str(Min) + "." + '0' + str(Sec)
            elif Sec <= 9 and Min <=9 and Hrs >=9:
                self.output = str(Hrs) + '.'+ '0' + str(Min) + "." + '0' + str(Sec)
            elif Sec <= 9 and Min >=9 and Hrs >=9:
                self.output = str(Hrs) + '.'+ str(Min) + "." + '0' + str(Sec)
            elif Sec >= 9 and Min >=9 and Hrs >=9:
                self.output = str(Hrs) + '.'+ str(Min) + "." + str(Sec)
            elif Sec >= 9 and Min >=9 and Hrs <=9:
                self.output = '0' + str(Hrs) +'.'+ str(Min) + "." + str(Sec)
            elif Sec >= 9 and Min <= 9 and Hrs <=9:
                self.output = '0' + str(Hrs) +'.'+ '0' + str(Min) + "." + str(Sec)
            elif Sec >= 9 and Min <=9 and Hrs >= 9:
                self.output = str(Hrs) +'.'+ '0' + str(Min) + "." + str(Sec)
            elif Sec <= 9 and Min >= 9 and Hrs <=9:
                self.output =  '0' + str(Hrs) +'.'+ str(Min) + "." + '0' + str(Sec)

class MainApp(App):        
    def build(self):
        c = MyApp()

        return c
if __name__ == '__main__':
    MainApp().run()  

mainapp.kv

<MyApp>:
    lbl1: label1
    BoxLayout:
        size: root.size
        Button:
            id: button1
            text: "Change text"
            on_press: root.count()
        Label:
            id: label1
            text: "hi"

I am aware of this: How to change text of a label in the kivy language with python

and this: https://groups.google.com/forum/#!topic/kivy-users/mdqPQYBWEU8

But neither seems to work for me.

Heiko
  • 37
  • 2
  • 10

2 Answers2

0

Blocking tasks such as time.sleep() together with an infinite loop are not GUI friendly since it lives in an event loop, so blocking tasks will not allow handling other events such as changing the size of the window, moving the window, etc.

Kivy can create periodic tasks without using True or time.sleep(), for this Clock is used:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock


class MyApp(BoxLayout):
    def __init__(self, **kwargs):
        super(MyApp, self).__init__(**kwargs)
        self.output = ''

    def update_label(self):
        self.lbl1.text = str(self.output)

    def count(self, *varargs):
        self.Sec = 0
        self.Min = 0
        self.Hrs = 0
        Clock.schedule_interval(self.on_timeout, 1)

    def on_timeout(self, *args):
        self.update_label()
        self.Sec += 1
        if self.Sec == 60:
            self.Sec = 0
            self.Min += 1
        if self.Min == 60:
            self.Min = 0
            self.Hrs += 1
        if self.Sec <= 9 and self.Min <=9 and self.Hrs <= 9:
            self.output = '0' + str(self.Hrs) +'.'+ '0' + str(self.Min) + "." + '0' + str(self.Sec)
        elif self.Sec <= 9 and self.Min <=9 and self.Hrs >=9:
            self.output = str(self.Hrs) + '.'+ '0' + str(self.Min) + "." + '0' + str(self.Sec)
        elif self.Sec <= 9 and self.Min >=9 and self.Hrs >=9:
            self.output = str(self.Hrs) + '.'+ str(self.Min) + "." + '0' + str(self.Sec)
        elif self.Sec >= 9 and self.Min >=9 and self.Hrs >=9:
            self.output = str(self.Hrs) + '.'+ str(self.Min) + "." + str(self.Sec)
        elif self.Sec >= 9 and self.Min >=9 and self.Hrs <=9:
            self.output = '0' + str(self.Hrs) +'.'+ str(self.Min) + "." + str(self.Sec)
        elif self.Sec >= 9 and self.Min <= 9 and self.Hrs <=9:
            self.output = '0' + str(self.Hrs) +'.'+ '0' + str(self.Min) + "." + str(self.Sec)
        elif self.Sec >= 9 and self.Min <=9 and self.Hrs >= 9:
            self.output = str(self.Hrs) +'.'+ '0' + str(self.Min) + "." + str(self.Sec)
        elif self.Sec <= 9 and self.Min >= 9 and self.Hrs <=9:
            self.output =  '0' + str(self.Hrs) +'.'+ str(self.Min) + "." + '0' + str(self.Sec)

class MainApp(App):        
    def build(self):
        c = MyApp()

        return c
if __name__ == '__main__':
    MainApp().run()  

Plus:

Instead of doing a tedious calculation to obtain the time we can reduce it using the libraries:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from datetime import datetime


class MyApp(BoxLayout):
    def count(self, *varargs):
        self.start = datetime.now()
        Clock.schedule_interval(self.on_timeout, 1)

    def on_timeout(self, *args):
        d = datetime.now() - self.start
        self.lbl1.text = datetime.utcfromtimestamp(d.total_seconds()).strftime("%H.%M.%S")

class MainApp(App):        
    def build(self):
        c = MyApp()

        return c
if __name__ == '__main__':
    MainApp().run()  
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
0

In your KV file the id is label1 but when you are updating, you are updating the text for lbl1.