Kivy ObjectProperty 更新标签文本

Posted

技术标签:

【中文标题】Kivy ObjectProperty 更新标签文本【英文标题】:Kivy ObjectProperty to update label text 【发布时间】:2014-03-04 06:43:27 【问题描述】:

我正在创建一个 kivy 用户界面来显示由我作为标准 python 对象编写的数据模型生成的值。本质上,我希望用户能够按下一个按钮,这将改变底层数据模型,并且这种改变的结果将自动更新和显示。据我了解,这可以使用 kivy 属性(在本例中为 ObjectProperty)来实现。

下面是一些示例代码:

import kivy
kivy.require('1.7.0')

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.properties import ObjectProperty
from kivy.lang import Builder

Builder.load_string("""
<RootWidget>:
    cols: 2
    Label:
        text: "Attribute a:"
    Label:
        text: root.data_model.a
    Label:
        text: "Attribute b:"
    Label:
        text: root.data_model.b
    Label:
        text: "Attribute c:"
    Label:
        text: root.data_model.c
    Button:
        text: "Make data_model.a longer"
        on_press: root.button_press()
    Button:
        text: "Make data_model.b shorter"
        on_press: root.button_press2()
""")


class DataModel(object):
    def __init__(self):
        self.a = 'This is a'
        self.b ='This is b'

    @property
    def c(self):
        return self.a + ' and ' + self.b

class RootWidget(GridLayout):
    data_model = ObjectProperty(DataModel())

    def button_press(self, *args):
        self.data_model.a = 'This is a and it is really long now'
        print self.data_model.c

    def button_press2(self, *args):
        self.data_model.b = 'B'
        print self.data_model.c

class TestApp(App):
    def build(self):
        return RootWidget()

app = TestApp()
app.run()

所需的结果是当用户按下任一按钮时,标签会自动更新以显示新属性。从打印语句可以看出,data_model 正在正确更新。但是,没有一个标签正在更新。有人可以澄清如何做到这一点吗?

【问题讨论】:

【参考方案1】:

但是,所有标签都没有更新。有人可以澄清如何做到这一点吗?

您引用的属性必须是 Kivy 属性,但您引用的 abc 都只是 python 属性,因此 Kivy 无法绑定到它们的更改。

要使用属性,您需要您的对象从 EventDispatcher 继承(Kivy 小部件会自动执行此操作,这就是它们的属性起作用的原因)。

from kivy.event import EventDispatcher

class DataModel(EventDispatcher):
    a = StringProperty('')
    b = StringProperty('')
    c = StringProperty('')

    def __init__(self, *args, **kwargs):
        super(DataModel, self).__init__(*args, **kwargs)
        self.a = 'This is a'
        self.b ='This is b'
        self.bind(a=self.set_c)
        self.bind(b=self.set_c)

    def set_c(self, instance, value):
        self.c = self.a + ' and ' + self.b        

请注意,这不是获得你想要的 c 行为的唯一方法(甚至不一定是最好的方法)。您可以使用 kv 语言创建绑定(我通常会这样做),或者您可以查看 Kivy 的 AliasProperty 以获得更类似于您的原始定义的内容。

当然你也可以在声明属性时设置 a 和 b 的值。

【讨论】:

这是个好主意,但对于我的具体问题,由于self.bind(a=self.set_c) 部分,它可能难以实现。具体来说,我的数据模型有一组非常复杂的相互关系,将 10 个输入变量映射到 30-40 个输出变量比我希望的要多。无论如何,谢谢你的想法。 你能指点我关于 AliasProperty 的内容吗?我发现 kivy 文档在其具体工作原理和用途方面有些欠缺。 AliasProperty 并不对应一个单一的属性,而实际上是一对在设置或访问时调用的函数。这些可以访问或修改其他属性,例如普通的 python 属性。【参考方案2】:

这是我的解决方案:

https://gist.github.com/jsexauer/8861079

本质上,我创建了一个连接数据模型和 UI 的包装类。我不喜欢它的一些地方,也许其他人可以改进:

任何更新底层数据模型的 UI 函数都必须使用 UI_DataModel 类提供的“更新”装饰器进行装饰。最好不必包含该装饰器,尽管我不确定如何在不大幅修改 DataModel 类的工作方式的情况下做到这一点(但重点是您不必接触底层数据模型类) 我希望能够将通用数据模型实例传递给 UI_DataModel 的__init__(),而不是让它使用全局变量(因此是硬编码的)。我试图让它工作,但遇到了一个弱引用递归地狱。也许对 Python 对象模型有更好理解的人可以实现这一点。

【讨论】:

以上是关于Kivy ObjectProperty 更新标签文本的主要内容,如果未能解决你的问题,请参考以下文章

AttributeError:“kivy.properties.ObjectProperty”对象没有属性“manager1”

Kivy & pyvisa - 如何在 GPIB 连接后将 ObjectProperty 设置为 None?

ObjectProperty 类的使用

按“退出”时离开 kivy 应用程序

Kivy - 无法更改带有 id 的 .text

Kivy 标签未更新