KV語言容許你以聲明的方式建立控件樹,以及綁定控件屬性到其餘的控件或使用一種天然的方式進行回調。python
你能夠告訴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語言有三個特殊的關鍵字:
從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_x
與center_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__
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
經過使用一個逗號來分隔類名,全部的在聲明中列出的類將擁有一樣的屬性。
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()
#: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’