You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy框架中Label文本无法更新的技术求助

问题:Kivy界面Label文本无法随变量更新

问题描述

代码执行正常,但Kivy界面上的Label文本无法同步更新。data_PV变量初始值"toto"能正常显示,修改该变量后,Python的print输出显示变量已成功更新,但界面文本没有变化。

尝试方案

删除KV文件中text:root.data_PV语句,直接在Python代码中设置Label的text属性(已注释的两行代码),结果仍无法更新界面文本。

相关代码

Python代码

import ctypes
import sys
import time

from kivy.config import Config
Config.set('graphics','resizable', False)
#S9 2960 x 1440
n = 3
Config.set('graphics','width', str(int(1440/n)))
Config.set('graphics','height', str(int(2960/n)))
import kivy
from kivy.uix.popup import Popup
from kivy.app import App, StringProperty
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.progressbar import ProgressBar
from kivy.properties import ObjectProperty
from kivy.properties import NumericProperty
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen 
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
import paho.mqtt.subscribe as subscribe
import threading
from kivy.clock import mainthread

class MainWindow(Screen):
    pass

class PompeSurf1Window(Screen):
    freq_SP = ObjectProperty(TextInput)
    data_PV = StringProperty("toto")
        
    def update(self, loc_data,*a):
        self.data_PV = str(loc_data)
        print("valeur data:", self.data_PV)
        #self.freq_SP.text= str(self.data_PV)
        #self.ids.label_freq_PV.text=self.data_PV
        
    def pub_freq_SP(self):
        for i in range(1):
            text = "at#rtuw=1,6,8193,"+str(int(self.freq_SP.text)*100)
            publish.single("set", text, qos=0, retain= False, hostname="test.mosquitto.org")

class WindowManager(ScreenManager):
    pass    

kv = Builder.load_file('main.kv')

class LoivesApp(App):
    client = mqtt.Client()
    
    @mainthread
    def on_message(self,client, userdata, message):
        data=message.payload.decode("utf-8")
        print(data)
        instance1 = PompeSurf1Window()
        instance1.update(data)
           
    def build(self):
        client = mqtt.Client()
        self.client.on_message=self.on_message 
        self.client.connect('test.mosquitto.org',1883)
        self.client.loop_start()
        self.client.subscribe([("statusword2",0)])
        return kv
    
    def on_pause(self):
        pass
        
    def on_resume(self):
        self.client.on_message=self.on_message 
        self.client.connect('test.mosquitto.org',1883)
        self.client.loop_start()
        self.client.subscribe([("statusword2",0)])

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

KV代码

WindowManager:
    MainWindow:
    PompeSurf1Window:
    
<MainWindow>:
    name: "main"
    BoxLayout:
        orientation: "vertical"
        size: root.width, root.height
        spacing: 20
        padding: 20
        Label:
            text: "Ferme des Loives"
            font_size: 100
        Button:
            text: "Pompe Surface 1"
            font_size: 50
            size_hint: 0.8, 0.8
            pos_hint: {"x":0.1, "top":0.9}
            on_release:
                app.root.current = "Pompe1"
                root.manager.transition.direction = "left" # peut être right up down   
               
<PompeSurf1Window>:
    name: "Pompe1"
    spacing: 20
    padding: 20
    freq_PV: label_freq_PV
    freq_SP: input_freq_SP
    GridLayout:
        resizable: False
        cols: 1
        size: root.width, root.height
        spacing: 20
        padding: 20
        Label:
            size_hint_y: None
            height: 20 
        Label:
            text: "Pompe de Surface 1"
            font_size: 100
            size_hint_y: None
            height: 50    
        GridLayout:
            cols: 2
            Label:
                text: "Fréquence actuelle"
                font_size_hint: None
                font_size: 32
            Label:
                text: "Consigne de fréquence"
                font_size_hint: None
                font_size: 32
            
            Label:
                id: label_freq_PV
                text: root.data_PV
                font_size_hint: None
                font_size: 32

            TextInput:
                id: input_freq_SP
                font_size: 32
                multiline: False
                on_text_validate: root.pub_freq_SP()
            
        Button:
            text: "retour"
            size_hint: 0.8, 0.2
            pos_hint: {"x":0.1, "top":0.9}
            on_release:
                app.root.current = "main"
                root.manager.transition.direction = "right"

解决方案

核心问题在于你在on_message回调中新建了一个PompeSurf1Window实例,而不是操作界面上已经存在的那个实例。KV文件中已经通过WindowManager创建了PompeSurf1Window的实例,你新创建的实例和界面显示的完全是两个对象,修改新实例的data_PV自然不会影响界面。

修改LoivesApp类中的on_message方法:

@mainthread
def on_message(self,client, userdata, message):
    data=message.payload.decode("utf-8")
    print(data)
    # 替换新建实例的代码,获取屏幕管理器中已存在的PompeSurf1Window实例
    instance1 = self.root.get_screen("Pompe1")
    instance1.update(data)

解释

  • self.root是App返回的WindowManager实例,调用get_screen("Pompe1")可以获取KV中定义的、当前管理的PompeSurf1Window实例。
  • 对这个实例调用update方法修改data_PV,由于data_PV是StringProperty,会自动触发KV中text: root.data_PV的绑定更新,界面Label文本就会同步变化。
  • 保留@mainthread装饰器是正确的,因为MQTT回调运行在非主线程,Kivy的UI操作必须在主线程执行。

内容的提问来源于stack exchange,提问作者jmoupou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:39:53