Skip to content
Advertisement

I can’t update the content of a Kivy label from Python

I state that this is the first time I use Kivy. The code I attached works, the only problem is that the lbl label does not update automatically but only if I press the update button. In practice, if I call the update_lbl function via the “update” button it works, when it is called automatically by unpacking_msg it does nothing.

from email import message
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.lang import Builder
from numpy import empty
import paho.mqtt.client as mqttClient
from queue import Queue
import threading

q=Queue()
incoming_message =''
incoming_topic =''

class Manager(ScreenManager):
    pass

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

class HomeScreen(Screen):

    pass

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

class MsgDecoder ():
    
    def __init__(self,msg):
        self.msg = msg
    
    def unpacking_msg(self):
        global incoming_message
        global incoming_topic
        incoming_topic =  str(self.msg.topic)
        incoming_message = str(self.msg.payload.decode("utf-8"))
        MainApp().update_lbl()
        
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

class MqttApp():

    def __init__(self,broker_address,port,user,password):   
        self.password = password
        self.user = user
        self.port = port
        self.broker_address = broker_address
       
    broker_address = "broker.hivemq.com"    
    port = 1883                   
    user = ""                  
    password = ""   

    try:
        client = mqttClient.Client(clean_session=True, userdata=True)               
        client.username_pw_set(user , password) 
        client.connect(broker_address,port)
        client.loop_start() 
    except:
        pass
        
    def on_connect(client, userdata, flags, rc):
        client.subscribe("kivy")

    def on_message(client, userdata, msg):
        q.put(msg)        
                    
    client.on_connect = on_connect
    client.on_message = on_message

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

class MainApp(App):  
    
    lbl_txt = StringProperty()

    def __init__(self):
            super(MainApp, self).__init__()
            self.lbl_txt = ("No message")
    
    def switch_callback(self, switchObject, switchValue):
        
        if(switchValue):
            MqttApp.client.publish("kivy", "ON")
        else:
            MqttApp.client.publish("kivy", "OFF") 

    def update_lbl(self, *args):
        self.lbl_txt=incoming_message 

 #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::  

def get_msg ():
    threading.Timer(1.0, get_msg).start()
    while not q.empty():
        msg = q.get()
        if msg is None:
            continue
        md= MsgDecoder(msg)
        md.unpacking_msg()
get_msg()

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

Here is the Kivy file:

ScreenManager:
    HomeScreen:
        id: 'homescreen'
        
    
<HomeScreen>:
    swc: swc
    
    BoxLayout:
       

        orientation: 'vertical'
        spacing: 50
        padding: 100

        Label:
            text: 'Remote Lamp'

        Switch:
            id:swc
            on_active: app.switch_callback(*args)

        Button:
            text: "update"
            on_press: app.update_lbl()    

        Label:
            id: lbl
            text: app.lbl_txt

I really appreciate any other helpful advice! I am not an expert as you can see.

Advertisement

Answer

The problem is that your code:

MainApp().update_lbl()

is creating a new instance of MainApp and calling its update)lbl() method. However, that new instance of MainApp is not the instance that you see on the screen. You must call the update_lbl() method of the running App. You can do that by using the get_running_app() method. See the documentation. Try this replacement for the above line:

App.get_running_app().update_lbl()
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement