2014-02-07 73 views
9

我正在創建一個kivy用戶界面來顯示由我寫爲標準python對象的數據模型生成的值。實質上,我希望用戶能夠按下一個按鈕,這會改變底層的數據模型,並且這個更改的結果會自動更新和顯示。這是我的理解,這可以使用kivy屬性(在這種情況下,ObjectProperty)實現。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() 

期望的結果是,用於當用戶按下任一按鈕時,標籤會自動更新以顯示新的屬性。從print語句可以看出,data_model得到了正確的更新。但是,沒有任何標籤正在更新。有人可以澄清如何做到這一點?

回答

6

但是,沒有標籤正在更新。有人可以澄清如何做到這一點?

您引用需要被Kivy性質的屬性,但abc你引用都只是蟒蛇屬性,以便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的值。

+0

這是一個好主意,但我的具體的問題可能很難,因爲'''self.bind(A = self.set_c)'''部分來實現。具體來說,我的數據模型有一套非常複雜的內部關係,並將10個輸入變量映射到30-40個輸出變量的數量比我希望我必須要做的要多。無論如何,謝謝你的想法。 – jsexauer

+0

你能指點我一些關於AliasProperty的東西嗎?我發現kivy文檔對於它的工作原理以及它的目的有點缺乏。 – jsexauer

+0

AliasProperty不對應於單個屬性,但實際上是一對在設置或訪問時調用的函數。這些可能會訪問或修改其他屬性,如普通的python屬性。 – inclement

3

這裏是我的解決方案:

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

在本質上我創建了一個橋樑的數據模型和用戶界面的包裝類。有幾件事情,我不喜歡它的原因,也許其他一些人將能夠加以改進:

  • 哪些更新基礎數據模型中的任何UI功能必須與提供的「更新」裝飾裝飾UI_DataModel類。不需要包含那個裝飾器是理想的,但我不確定如何在沒有實質性修改DataModel類的工作方式的情況下如何做到這一點(但是其中的重點是不必觸摸底層數據模型類)
  • 我想能夠將公共數據模型實例傳遞給UI_DataModel的__init__()代替具有它使用全局變量(並且因此是硬編碼)。我試圖讓這個工作,但遇到了一個weakref遞歸地獄。也許有人更好地理解Python對象模型可以實現這一點。