Search code examples
pythonlabelkivyupdating

Kivy change label text with python


I'm semi-OK with Python but brand new to Kivy, I know my problem is referencing the label ID but I can't seem to solve it and searching doesn't seem to give me what I need.

I'm trying to get a label to display the current time, so I know I have the right framework in terms of updating etc but I'm sure its all down to referencing the label ID somehow and its that I'm struggling with?

The following code runs fine, displays the labels etc until I try to update the label_text.text at which point i get an error: AttributeError: 'float' object has no attribute 'lbl_time'. I've tried str(time.strftime("%H:%M:%S")) but that doesn't solve it.

from kivy.app import App
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.properties import ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition, FadeTransition
from kivy.uix.anchorlayout import AnchorLayout
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
import time
from datetime import datetime

class MainScreen(Screen):

def update_time(self):
    lbl_time = ObjectProperty()
    MyTime = time.strftime("%H:%M:%S")
    self.lbl_time.text = MyTime

class DetailScreen(Screen):
    pass

class SettingsScreen(Screen):
    pass

class MyScreenManager(ScreenManager):
    pass



root_widget = Builder.load_string('''
    MyScreenManager:
    MainScreen:
    DetailScreen:
    SettingsScreen:

<MainScreen>:
    name: 'main'
    BoxLayout:
        orientation: 'vertical'
        Label:
            id: lbl_time
            text: 'Time' 
            font_size: 60
        Label:
            text: 'Main2'
            font_size: 30
        GridLayout:
            cols: 2
            Label:
                text: 'Bottom'
                font_size: 30
            Label:
                text: 'Bottom1'
                font_size: 30

 <DetailScreen>:
     name: 'details'

 <SettingsScreen>:
     name: 'settings'

 ''')
 class ScreenManagerApp(App):

     def build(self):
         return root_widget

     def on_start(self):
         Clock.schedule_interval(MainScreen.update_time, 1)

 ScreenManagerApp().run()

Solution

  • This was more of a Python problem rather than a Kivy one. You were calling the update_time of the class MainScreen class, not of the object/instance of the MainScreen. Basically, you would need to save a reference to the object (self.main_screen) in the build method, and then use it in the on_start.

    class ScreenManagerApp(App):
    
        def build(self):
            self.main_screen = MainScreen()
            return self.main_screen
    
        def on_start(self):
            Clock.schedule_interval(self.main_screen.update_time, 1)
    

    Also you cannot access id outside of the kv language, i.e. in the python. You have to reference the id by adding a property, e.g. the_time:

    <MainScreen>:
        name: 'main'
        the_time: _id_lbl_time
        BoxLayout:
            orientation: 'vertical'
            Label:
                id: _id_lbl_time
    

    A minor problem is that the update_time() receives to parameters. Also, there were quite a few weird things in your code, so I couldn't run the code. I fixed all the above in the code below:

    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.screenmanager import Screen
    from kivy.properties import ObjectProperty, StringProperty
    from kivy.clock import Clock
    import time
    from datetime import datetime
    
    Builder.load_string('''
    <MainScreen>:
        name: 'main'
        the_time: _id_lbl_time
        BoxLayout:
            orientation: 'vertical'
            Label:
                id: _id_lbl_time
                text: 'Time' 
                font_size: 60
     ''')
    
    class MainScreen(Screen):
    
        def update_time(self, sec):
            MyTime = time.strftime("%H:%M:%S")
            self.the_time.text = MyTime
    
    
    class ScreenManagerApp(App):
    
        def build(self):
            self.main_screen = MainScreen()
            return self.main_screen
    
        def on_start(self):
            Clock.schedule_interval(self.main_screen.update_time, 1)
    
    ScreenManagerApp().run()