Kivy模板語言KV說明

語言概念

KV語言容許你以聲明的方式建立控件樹,以及綁定控件屬性到其餘的控件或使用一種天然的方式進行回調。python

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

如何加載kv文件

你能夠告訴Kivy直接加載一個字符串或一個文件。若是這個字符串或文件定義了一個根控件,它將被下面的方法返回:canvas

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

或者ide

Builder.load_string(kv_string)ui

內容規則

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

你能夠以以下方式聲明你的根控件類:spa

Widget:設計

使用以下方式聲明其餘控件:code

<MyWidget>:orm

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.before 和 canvas.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’
相關文章
相關標籤/搜索