Kivy ObjectProperty para actualizar el texto de la etiqueta

Estoy trabajando en la creación de una interfaz de usuario kivy para mostrar los valores generados por un modelo de datos que he escrito como un objeto estándar de Python. En esencia, me gustaría que el usuario pudiera presionar un botón, lo que cambiaría el modelo de datos subyacente y los resultados de este cambio se actualizarían y mostrarían automáticamente. Tengo entendido que esto puede implementarse utilizando las propiedades de Kivy (en este caso, ObjectProperty).

Aquí hay un código de ejemplo:

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(""" : 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() 

El resultado deseado es para cuando el usuario presiona cualquiera de los botones, las tags se actualizarán automáticamente para mostrar las nuevas propiedades. Como pueden ver las instrucciones de impresión, el data_model se está actualizando correctamente. Sin embargo, ninguna de las tags se está actualizando. ¿Alguien puede aclarar cómo hacer esto?

Sin embargo, ninguna de las tags se está actualizando. ¿Alguien puede aclarar cómo hacer esto?

Los atributos a los que hace referencia deben ser propiedades de Kivy, pero a , b y c que hace referencia son todos atributos de python, por lo que Kivy no tiene forma de vincularse a sus cambios.

Para trabajar con propiedades, necesita que su objeto se herede de EventDispatcher (los widgets de Kivy lo hacen automáticamente, por lo que sus propiedades funcionan).

 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 

Tenga en cuenta que esta no es la única manera (o incluso necesariamente la mejor) de obtener el comportamiento que desea para c. Puede crear el enlace en lenguaje kv (normalmente lo haría de esa manera) o puede buscar en AliasProperty de Kivy para obtener algo más parecido a su definición original.

Por supuesto, también puede establecer los valores de a y b cuando se declaran las propiedades.

Aquí está mi solución:

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

En esencia, creé una clase de contenedor que une el modelo de datos y la interfaz de usuario. Hay algunas cosas que no me gustan de las que quizás otras personas puedan mejorar:

  • Cualquier función de UI que actualice el modelo de datos subyacente debe estar decorada con el decorador de “actualización” proporcionado por la clase UI_DataModel. Sería ideal no tener que incluir a ese decorador, aunque no estoy seguro de cómo hacerlo sin modificar sustancialmente la forma en que funciona la clase DataModel (pero el punto principal de esto es que no debería tener que tocar el modelo de datos subyacente). clase)
  • Me gustaría poder pasar la instancia del modelo de datos común al __init__() de UI_DataModel en lugar de utilizar una variable global (y por lo tanto está codificada). Traté de hacer que esto funcionara, pero me encontré con un débil infierno de recursión. Tal vez alguien que tenga una mejor comprensión del Modelo de objetos de Python podría implementar esto.