『Python Kivy』Kivy模板語言KV說明


語言概念

KV語言允許你以聲明的方式創建控件樹,以及綁定控件屬性到其他的控件或使用一種自然的方式進行回調。

  • 它允許非常快速並靈活的改變你的UI。
  • 它還可以讓你的應用程序與應用程序的界面進行分隔。

如何加載kv文件

你可以告訴Kivy直接加載一個字符串或一個文件。如果這個字符串或文件定義了一個根控件,它將被下面的方法返回:

Builder.load_file('path/to/file.kv)

或者

Builder.load_string(kv_string)

內容規則

KV源自規則的搭建,這些規則被用於描述一個Widget的內容,你可以有一個根規則,以及一些類或模板規則。

你可以以如下方式聲明你的根控件類:

Widget:

使用如下方式聲明其他控件:

<MyWidget>:

KV語言有三個特殊的關鍵字:

  • app: 總是與你的應用關聯
  • root: 與當前控件的根控件關聯
  • self: 與控件關聯

特殊符號

從python中實現一些功能:

#:import name x.y.z

等價於:

from x.y import z as name

設置一個全局值:

#:set name value

等價於:

name = value

示例

MyRootWidget:
    BoxLayout:
        Button:
        Button:

等價於:

root = MyRootWidget()
box = BoxLayout()
box.add_widget(Button())
box.add_widget(Button())
root.add_widget(box)

賦值:

GridLayout:
    cols: 3

等價於:

grid = GridLayout(cols=3)

以及

GridLayout:
    cols: len(root.data)

等價於:

grid = GridLayout(cols=len(self.data))
self.bind(data=grid.setter('cols'))

事件綁定

Widget:
    on_size: my_callback()

你可以使用args關鍵字來傳送值:

TextInput:
    on_text: app.search(args[1])

更復雜的表達式:

pos: self.center_x - self.texture_size[0] / 2., self.center_y - self.texture_size[1] / 2.

這個表達式監聽center_xcenter_y以及texture_size的變化。如果它們變化了,表達式會重新計算並更新pos字段。

你也可以處理on_事件在你的kv語言中。例如TextInput類有一個焦點屬性,這個屬性可以使用如下的方式訪問:

TextInput:
    on_focus: print(args)

擴展畫板

KV語言可以用於定義你的控件的畫板結構:

MyWidget: 
    canvas:
        Color:
            rgba: 1, .3, .8, .5
        Line:
            points: zip(self.data.x, self.data.y)

並且當屬性值改變化,它們進行更新:

當然,你也可以使用 canvas.beforecanvas.after.

引用其他控件

在一個控件樹中,經常需要訪問/引用別的控件。KV語言提供一種方式來實現,使用id。將他們當成一個類級別變量,這僅能夠用於KV語言中。考慮下面的示例:

<MyFirstWidget>:
    Button:
        id: f_but
    TextInput:
        text: f_but.state

<MySecondWidget>:
    Button:
        id: s_but
    TextInput:
        text: s_but.state

id被限制在它被定義的范圍內,所以在上面的代碼中s_but不能被上面的<MySecondWidget>訪問。

一個id是一個到控件的弱引用並不是這個控件本身。正因如此,存儲id對於在垃圾回收中保持控件是不夠的。如:

<MyWidget>
    label_widget: label_widget
    Button:
        text: 'Add Button'
        on_press: root.add_widget(label_widget)
    Button:
        text: 'Remove Button'
        on_press: root.remove_widget(lable_widget)
    Label:
        id: label_widget
        text: 'widget'

雖然一個關聯到label_widget存儲在MyWidget中,但是當另外的引用已經被使用后,還不足以保持這個對象的存活,因為它僅僅是一個弱引用。

因此,在移除按鈕被點擊后,窗口被重新調整尺寸,當添加按鈕被點擊以添加控件,一個ReferenceError將會產生:弱引用對象不存在將被拋出。

為了保持控件存活,一個到label_widget的直接引用必須被保持。在這個例子中,使用id.__self__label_widget.__self__來達到這一效果。正確的方法是:

<MyWidget>
    label_widget: label_widget.__self__

在你的Python代碼中,訪問已經被定義在KV語言中的控件

KV示例:

<MyFirstWidget>:
    # both these variables can be the same name and this doesn’t lead to 
    # an issue with uniqueness as the id is only accessible in kv. 
    txt_inpt: txt_inpt
    Button:
        id: f_but 
    TextInput:
        id: txt_inpt
        text: f_but.state
        on_text: root.check_status(f_but)

在python代碼中調用:

# ...
class MyFirstWidget(BoxLayout):
    txt_inpt = ObjectPropery(None)

    def check_status(self, btn):
        print('button state is : {state}'.format(state=btn.state))
        print('text input text is :{txt}'.format(txt=self.txt_input))

或者在KV中:

<Marvel>
    Label:
        id: loki
        text: 'loki: I AM YOUR GOD!'
    Button:
        id: hulk
        text: "press to smash loki"
        on_release: root.hulk_smash()

在Python中:

當你的KV文件已經被解析,Kivy使用ids收集所有的控件標簽,並且將放在self.ids字典中。這意味着你也可以遍歷這個控件並訪問他們。

class Marvel(BoxLayout):
    def hulk_smash(self):
        self.ids.hulk.text = "hulk: puny god!"
        self.ids.loki.text = "loki: >_<!!!"

        # ...

        for key, val in self.ids.items():
            print("key={0}, val={1}".format(key, val))

動態類

<MyWidget>: 
    Button:
        text: "Hello world, watch this text wrap inside the button" 
        text_size: self.size
        font_size: ’25sp’
        markup: True
    Button:
        text: "Even absolute is relative to itself" 
        text_size: self.size
        font_size: ’25sp’
        markup: True
    Button:
        text: "Repeating the same thing over and over in a comp = fail" text_size: self.size
        font_size: ’25sp’
        markup: True
    Button:

代替為每一個按鈕的屬性重復設置同樣的值,我們可以僅僅使用一個__模板__,如下所示:

<MyBigButt@Button>: 
    text_size: self.size 
    font_size: ’25sp’ 
    markup: True

<MyWidget>: 
    MyBigButt:
        text: "Hello world, watch this text wrap inside the button" 
    MyBigButt:
        text: "Even absolute is relative to itself" 
    MyBigButt:
        text: "repeating the same thing over and over in a comp = fail"
    MyBigButt:

這個類僅僅被這條規則的聲明所創建,從Button類繼承並在沒有在Python代碼中添加新的代碼的情況下,允許我們改變默認的值並為所有它的實例創建綁定。

在多個控件中重復使用樣式

my.kv文件:

<MyFirstWidget>: 
    Button:
        on_press: self.text(txt_inpt.text) 
    TextInput:
        id: txt_inpt 

<MySecondWidget>:
    Button:
        on_press: self.text(txt_inpt.text)
    TextInput:
        id: txt_inpt

myapp.py文件:

class MyFirstWidget(BoxLayout): 
    def text(self, val):
        print(’text input text is: {txt}’.format(txt=val)) 

class MySecondWidget(BoxLayout):
    writing = StringProperty(’’)
    def text(self, val): 
        self.writing = val

因為所有類共享同樣的.kv樣式,如果我們為所有的控件復用樣式,這個設計能夠被簡化。你可以在.kv中像下面這樣實現:

<MyFirstWidget,MySecondWidget>: 
    Button:
        on_press: self.text(txt_inpt.text) 
    TextInput:
        id: txt_inpt

通過使用一個逗號來分隔類名,所有的在聲明中列出的類將擁有同樣的屬性。

使用Kivy語言進行設計

在py文件中

import kivy 
kivy.require(’1.8.0’)

from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty

class Controller(FloatLayout):
    ’’’Create a controller that receives a custom widget from the kv lang file.
    Add an action to be called from the kv lang file. ’’’
    
    label_wid = ObjectProperty()
    info = StringProperty()

    def do_action(self):
        self.label_wid.text = ’My label after button press’
        self.info = ’New info text’

    class ControllerApp(App): 
        def build(self):
            return Controller(info=’Hello world’)
    if __name__ == ’__main__’: 
        ControllerApp().run()

controller.kv中進行設計

#:kivy 1.8.0

<Controller>:
    label_wid: my_custom_label

    BoxLayout:
        orientation: ’vertical’ 
        padding: 20
    Button:
        text: ’My controller info is: ’ + root.info 
        on_press: root.do_action()
    Label:
        id: my_custom_label
        text: ’My label before button press’


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM