Kivy ObjectProperty для обновления текста метки

Я работаю над созданием пользовательского интерфейса 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 корректно обновляется. Тем не менее, ни один из ярлыков не обновляется. Может кто-нибудь уточнить, как это сделать?

2 ответа

Решение

Тем не менее, ни один из ярлыков не обновляется. Может кто-нибудь уточнить, как это сделать?

Атрибуты, на которые вы ссылаетесь, должны быть свойствами Kivy, но a, b а также c вы ссылаетесь на все атрибуты 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 (я бы обычно так делал) или вы можете посмотреть на AliasProperty Kivy, чтобы найти нечто более похожее на ваше первоначальное определение.

Конечно, вы также можете установить значения a и b, когда свойства объявлены.

Вот мое решение:

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

По сути, я создал класс-оболочку, который связывает модель данных и пользовательский интерфейс. Есть несколько вещей, которые мне не нравятся в этом, и, возможно, некоторые другие люди смогут улучшить их:

  • Любая функция пользовательского интерфейса, которая обновляет базовую модель данных, должна быть украшена декоратором "update", предоставляемым классом UI_DataModel. Было бы идеально не включать этот декоратор, хотя я не уверен, как это сделать без существенного изменения работы класса DataModel (но весь смысл в том, что вам не нужно касаться базовой модели данных учебный класс)
  • Я хотел бы иметь возможность передать общий экземпляр модели данных в __init__() UI_DataModel вместо того, чтобы использовать глобальную переменную (и, следовательно, жестко запрограммирован). Я попытался заставить это работать, но натолкнулся на адский рекурсивный ад. Может быть, кто-то, кто лучше понимает объектную модель Python, может реализовать это.
Другие вопросы по тегам