2023年9月4日 星期一

Kivy property篇 概述

介紹

kivy屬性(kivy's Properties)是一種在類中定義屬性的方式,與傳統python屬性不同的是,kivy屬性發生改變的時候能觸發事件,這是非常方便的,因此kivy鼓勵以此方式宣告屬性,我們來看看以下範例:

在main.py中寫上此段程式碼:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty


class MyLayout(FloatLayout):
    a1 = NumericProperty(0)

    def btn1(self):
        self.a1 = 1

    def on_a1(self, instance, x):
        print('a1 is change to',x)


class Myapp(App):

    def build(self):
        return MyLayout()


if __name__ == '__main__':
    Myapp().run()

在以上程式碼中,我在MyLayout類中加入kivy屬性a1,指定其為NumericProperty類,其值為1;當呼叫btn1方法時,可使a1屬性為1;當呼叫on_a1時,print('button is change',x)

(注意!!!方法命名時必須是on_加上kivy屬性物件,以上為例,為了讓a1改變時自動觸發方法,我讓方法名稱設為on_a1,若取名不符此規則則無法觸發)

在my.kv中寫上此段程式碼::

<MyLayout>:

    Button:
        id: mybutton
        text: 'press me'
        on_press: root.btn1()

在以上程式碼中,我在Button部件中宣告當此Button被按下時,呼叫btn1方法,更改a1屬性

執行結果如下:

可以看到當我第一次按下Button時,pyvharm輸出'a1 is change to 1'字串,邏輯順序為:(1)按下Button觸發btn1方法(2)btn1方法使得a1從0更改為1(3)因a1更改,觸發on_a1方法,使得pycharm輸出'a1 is change to 1'(4)當我第二次按下Button時,a1物件沒有更改,因此不觸發on_a1方法。

kivy屬性在呼叫屬性與方法時也與傳統python的呼叫方法不同。傳統的python會這樣呼叫屬性與方法(此處以BoundedNumericProperty為例):

class MyLayout(FloatLayout):
    a1 = BoundedNumericProperty(0, min=-5, max=5)

    def btn1(self):
        self.a1.set_min(self, -10)
        print(self.a1.get_min(self))
        print(self.a1.bounds)
        self.a1 = self.a1-1

若執行以上程式碼會出錯,self.a1指的是值(在此例中為0)。在類(MyLayout)中想要呼叫kivy屬性的屬性與方法時必須使用property()方法

以下程式碼為正確使用方法

class MyLayout(FloatLayout):
    a1 = BoundedNumericProperty(0, min=-5, max=5)

    def btn1(self):
        self.property('a1').set_min(self, -10)
        print(self.property('a1').get_min(self))
        print(self.property('a1').bounds) 
        self.a1 = self.a1-1

在kivy屬性中,若輸入的值不符合對應的kivy屬性限制,將回傳ValueError,例如以下程式碼:

在main.py中寫上此段程式碼:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import BoundedNumericProperty


class MyLayout(FloatLayout):
    a1 = BoundedNumericProperty(0, min=-5, max=5)

    def btn1(self):
        self.property('a1').set_min(self, -10)
        print(self.property('a1').get_min(self))
        print(self.property('a1').bounds) 
        self.a1 = self.a1-1

    def on_a1(self, instance, x):
        print('a1 is change to',x)


class Myapp(App):

    def build(self):
        return MyLayout()


if __name__ == '__main__':
    Myapp().run()

在my.kv中寫上此段程式碼::

<MyLayout>:

    Button:
        id: mybutton
        text: 'press me'
        on_press: root.btn1()

執行結果如下:

若要設定成當回傳ValueError時將kivy屬性自動設定成某值,可以用以下兩種方式設定:

1.a1 = BoundedNumericProperty(0, min=-5, max=5,errorvalue=某值)

在main.py中寫上此段程式碼:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import BoundedNumericProperty


class MyLayout(FloatLayout):
    a1 = BoundedNumericProperty(0, min=-5, max=5, errorvalue=4)

    def btn1(self):
        self.property('a1').set_min(self, -10)
        print(self.property('a1').get_min(self))
        print(self.property('a1').bounds) 
        self.a1 = self.a1-1

    def on_a1(self, instance, x):
        print('a1 is change to',x)


class Myapp(App):

    def build(self):
        return MyLayout()


if __name__ == '__main__':
    Myapp().run()

在my.kv中寫上此段程式碼::

<MyLayout>:

    Button:
        id: mybutton
        text: 'press me'
        on_press: root.btn1()

執行結果如下:

2.a1 = BoundedNumericProperty(0, min=-5, max=5,errorhandler=lambda)

在main.py中寫上此段程式碼:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import BoundedNumericProperty


class MyLayout(FloatLayout):
    a1 = BoundedNumericProperty(0, min=-5, max=5, errorhandler=lambda x: 4 if x < -10 else -500)

    def btn1(self):
        self.property('a1').set_min(self, -10)
        print(self.property('a1').get_min(self))
        print(self.property('a1').bounds) 
        self.a1 = self.a1-1

    def on_a1(self, instance, x):
        print('a1 is change to',x)


class Myapp(App):

    def build(self):
        return MyLayout()


if __name__ == '__main__':
    Myapp().run()

在my.kv中寫上此段程式碼::

<MyLayout>:

    Button:
        id: mybutton
        text: 'press me'
        on_press: root.btn1()

執行結果如下:

為何property重要?

如上所述,kivy屬性發生改變的時候能觸發事件,不需要自己定義,若不想觸發任何事件,則省略定義事件過程就好,這是非常方便的,而且在kivy官方文檔中大多數的屬性都用kivy屬性,學好kivy屬性可以更好理解官方文檔,使程式碼更簡潔。

kivy官方發布的property總共有以下幾種,分別是:

AliasProperty

BooleanProperty

BoundedNumericProperty

ColorProperty

ConfigParserProperty

DictProperty

ListProperty

NumericProperty

ObjectProperty

OptionProperty

ReferenceListProperty

StringProperty

VariableListProperty

Property篇學習方法與順序

在Property篇中,由於各個Property差異極大,重複的地方很少,因此Property篇介紹的順序為:先介紹個別Property專門的用法,最後在'Kivy Property篇 Property講解'中講解所有Property都可以使用的用法。

沒有留言:

張貼留言

精選文章

Kivy UIX篇 widget篇 TabbedPanel類 event篇 講解