翻译:kivy语言
2017-07-17 00:23
169 查看
Programming Guide » Kv language¶
Concept behind the language¶
As your application grow more complex, it’s common that the construction ofwidget trees and explicit declaration of bindings, becomes verbose and hard tomaintain. TheKV Language is a attempt to overcome these short-comings.由于你的app越来越复杂,一般来说widget树的建造和明确声明的绑定,这个变成了沉重的负担并很难去维护。KV 语言尝试克服这些短板。
The KV language (sometimes called kvlang, or kivy language), allows you tocreate your widget tree in a declarative way and to bind widget propertiesto each other or to callbacks in a natural manner. It allows for very fastprototyping and agile
changes to your UI. It also facilitates a goodseparation between the logic of your application and its User Interface.
KV语言,允许你以声明的形式去创建你的widget树,并以比较自然的方式绑定widget属性给每个或者是callback。它可以快速的塑造一个原型并灵活地改变你的ui。它也很好帮助分开你的app跟用户接口的逻辑。
How to load KV¶
There are two ways to load Kv code into your application:By name convention:通过名字
Kivy looks for a Kv file with the same name as your App class inlowercase, minus “App” if it ends with ‘App’ e.g:
MyApp -> my.kv
小写,只留着App前头的字眼
If this file defines a Root Widget it will be attached to the App’srootattribute and used as the base of the application widget tree.
如果这个文件定义为根widget,它将隶属于App的根属性并且作为一个app widget树的基础。
Builder:You can tell Kivy to directly load a string or a file. If this string or filedefines a root widget, it will be returned by the method:
Builder:你可以直接告诉kivy从一个字符串或者文件里头加载。如果字符串或者文件定义了根widget,它将会被这方法返回:
Builder.load_file('path/to/file.kv')
or:
Builder.load_string(kv_string)
Rule context¶
语句规则A Kv source constitutes of rules, which are used to describe the contentof a Widget, you can have oneroot rule, and any number ofclass ortemplate rules.
The root rule is declared by declaring the class of your root widget, withoutany indentation, followed by: and will be set as theroot attribute of theApp instance:
一个 KV最初的构成或者规则,是被用作定义widget的内容,你可以有个根规则,并且可以有任意数量的类或者规则模板。
Widget:
A class rule, declared by the name of a widget class between
< > andfollowed by :, defines how any instance of that class will begraphically represented:
属于类的规则,在<>中的名字声明,并后面紧跟一个冒号,定义了接下来有多少个类将被生动地表现出来:
<MyWidget>:
Rules use indentation for delimitation, as python, indentation should be offour spaces per level, like the python good practice recommendations.
规则使用缩进来划分界限,就如python一样。
There are three keywords specific to Kv language:
app: always refers to the instance of your application.
app:总是涉及关联到你app的实例
root: refers to the base widget/template in the current ruleroot:涉及关联到当前规则下的base widget/template
self: always refer to the current widgetself,总是涉及关联当前的widget
Special syntaxes¶特殊语法
There are two special syntaxes to define values for the whole Kv context:To access python modules and classes from kv,
这里有2种特殊语法去定义整个KV语境的值:
一个是访问来自kv的类,一个是访问python的模块
#:import name x.y.z #:import isdir os.path.isdir #:import np numpy
is equivalent to:
from x.y import z as name from os.path import isdir import numpy as np
in python.
To set a global value,
#:set name value
is equivalent to:
name = value
in python.
Instantiate children¶实例化
To declare the widget has a child widget, instance of some class, just declarethis child inside the rule:声明这个widget有一个 子widget,其实就是一些类的实例化,仅仅参考这条规则,声明这个child:
MyRootWidget:BoxLayout:Button:Button:
The example above defines that our root widget, an instance of MyRootWidget,which has a child that is an instance of the
BoxLayout.
That BoxLayout further has twochildren, instances of the
Buttonclass.
上述例子定义了我们的根widget,其实就是MyRootWidget的一个实例,这个实例会有一个child:也就是BoxLayout的实例。那么BoxLayout会有两个children:也就是Button的实例
A python equivalent of this code could be:
python实现的语句:
root = MyRootWidget() box = BoxLayout() box.add_widget(Button()) box.add_widget(Button()) root.add_widget(box)
Which you may find less nice, both to read and to write.python语句看起来缺点多多。
Of course, in python, you can pass keyword arguments to your widgets atcreation to specify their behaviour. For example, to set the number of columnsof a
gridlayout,
we would do:
当然,python中,你可以在创建的时候传递键的属性到你的widget ,去定义它们的行为。例如,设定gridlayout的列数:
grid = GridLayout(cols=3)
To do the same thing in kv, you can set properties of the child widget directlyin the rule:
在kv怎么做?同样你可以直接为子widget设置属性:
GridLayout: cols: 3
The value is evaluated as a python expression, and all the properties used inthe expression will be observed, that means that if you had something like thisin python (this assumeself is a widget with adata
ListProperty):
这个值同等于python的表达方式,并且这种形式的声明会发现到所有的属性,也意味着在python中有的(假设self 是一个widget并带有ListProperty数据):
grid = GridLayout(cols=len(self.data)) self.bind(data=grid.setter('cols'))
To have your display updated when your data change, you can now have just:
为了当你数据改变时候你的显示也可以更新到,你现在可以:
GridLayout: cols: len(root.data)
Note
Widget names should start with upper case letters while property namesshould start with lower case ones. Following thePEP8
Naming Conventionsis encouraged.
Widget命名应该开头字母大小,属性名就要小写。这里是命名规则:
Event Bindings¶事件绑定
You can bind to events in Kv using the “:” syntax, that is, associating acallback to an event:你可以绑定事件通过使用 冒号 这个语法,连接一个callback到事件当中:
Widget:on_size: my_callback()
You can pass the values dispatched by the signal using the args keyword:
你可以传递一个已被一个 信号源派遣的值(这个信号源使用了键这个变量)
TextInput: on_text: app.search(args[1])
More complex expressions can be used, like:
更加复杂的表达:
pos: self.center_x - self.texture_size[0] / 2., self.center_y - self.texture_size[1] / 2.
This expression listens for a change in
center_x,
center_y,and
texture_size.
If one of them changes, the expression will bere-evaluated to update the
posfield.
You can also handle
on_events inside your kv language.For example the TextInput class has a
focusproperty whose auto-generated
on_focus
event can be accessed inside the kv language like so:
这个表达监听
center_x,
center_y,and
texture_size的变化。如果其中一个改变了,表达式会重新求值并更新到pos域。
你也可以嵌入kv语言处理on事件。例如,TextInput类有个focus属性,这个属性自动生成的on_focus事件可以嵌入kv语言:
TextInput: on_focus: print(args)
Extend canvas¶扩展画布
Kv lang can be used to define the canvas instructions of your widget like this:Kv语言可被用来定义你widget的画布构造:
MyWidget:canvas:
Color:
rgba: 1, .3, .8, .5
Line:
points: zip(self.data.x, self.data.y)
And they get updated when properties values change.
Of course you can use canvas.before and canvas.after.
Referencing Widgets¶引用 Widget
In a widget tree there is often a need to access/reference other widgets.The Kv Language provides a way to do this using id’s. Think of them as classlevel variables that can only be used in the Kv language. Consider thefollowing:在widget树中,很常碰到要引用其他的widget,Kv语言提供了一种方式:id。考虑到它们作为一个类级别的变量,也就只能用在kv语言中。:
<MyFirstWidget>: Button: id: f_but TextInput: text: f_but.state <MySecondWidget>: Button: id: s_but TextInput: text: s_but.state
An
idis limited in scope to the rule it is declared in, so in thecode above
s_butcan not be accessed outside the
<MySecondWidget>rule.
id限制在声明的规则域中,所以,上述代码中的s_but不可以在
<MySecondWidget>规则外被引用使用。
Warning
When assigning a value to
id, remember that the value isn’ta string. There are no quotes: good ->
id:value,
bad ->
id:'value'
当赋值给id时,记住这个值不是一个字符串,没有这样的标注:正确的姿势->id:value,错误的姿势->[code]id:'value'
[/code]
An
idis a
weakrefto the widget and not the widget itself. As aconsequence, storing the
idis not sufficient to keep the widget from beinggarbage collected. To demonstrate:
id是一个
weakref(附注:)给到widget,所以不是一个widget它本身。因而,存储一个 id 不足以阻止widget被垃圾回收掉。
使用weakref模块,你可以创建到对象的弱引用,Python在对象的引用计数为0或只存在对象的弱引用时将回收这个对象。[code]
<MyWidget>:label_widget: label_widgetButton:
text: 'Add Button'
on_press: root.add_widget(label_widget)Button:
text: 'Remove Button'
on_press: root.remove_widget(label_widget)
Label:
id: label_widget
text: 'widget'
Although a reference to
label_widgetis stored in
MyWidget, it is notsufficient to keep the object alive once other references have
been removedbecause it’s only a weakref.Therefore, after the remove button is clicked (which removesany direct reference to the widget) and the window is resized (which calls thegarbage collector resulting in the deletion of
label_widget),
when the addbutton is clicked to add the widget back, a
ReferenceError:weakly-referencedobjectnolongerexists
will be thrown.
尽管一个对label_widget的引用被存于MyWidget,当其他的引用被移除后它还不足以让这个对象保持存活,因为它只是个weakref。因此,在移除按钮按下后(这个移除掉了widget所有的直接的引用)并且 窗口被调整了大小(这会唤醒垃圾回收器,导致对label_widget的删除),当增加按钮按下把这个 widget搞回来,此时异常抛出。
To keep the widget alive, a direct reference to the
label_widgetwidgetmust be kept. This is achieved using
id.__self__or
label_widget.__self__in this case.
The correct way to do this would be:
为了确保这个widget可以存活,一个对label_widget的直接引用必须被保留。在这个例子中,使用
id.__self__or
label_widget.__self__。
<MyWidget>:label_widget: label_widget.__self__
Accessing Widgets defined inside Kv lang in your python code¶kv语言跟python语言并用
Consider the code below in my.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)
In myapp.py:
... class MyFirstWidget(BoxLayout): txt_inpt = ObjectProperty(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_inpt)) ...
txt_inpt is defined as a
ObjectPropertyinitializedtoNone inside the Class.
txt_inpt被定义为
ObjectProperty初始化成None的类。
txt_inpt = ObjectProperty(None)
At this point self.txt_inpt is None. In Kv lang this property is updated tohold the instance of the
TextInputreferenced by the idtxt_inpt.:
那么self.txt_inpt 是None.在Kv语言中,通过id txt_inpt,这个属性要被更新,是为了去hold住TextInput的引用实例。
txt_inpt: txt_inpt
From this point onwards, self.txt_inpt holds a reference to the widgetidentified by the idtxt_input and can be used anywhere in the class, as inthe functioncheck_status. In contrast to this method you could also just
passtheid to the function that needs to use it, like in case of
f_but in thecode above.
基于这点,我们继续讨论,self.txt_inpt hold了一个到widget的引用(这个widget是从id txt_input定义的),并且可以被该类的任何地方使用,尽管是在内部方法体:check_status里头。对比这个方法,你也许会仅仅传递这个id到这个方法。
There is a simpler way to access objects with id tags in Kv using theids lookup object. You can do this as follows:
这里有个更为简单的方式,在kv中用id 标签去连接对象:
<Marvel> Label: id: loki text: 'loki: I AM YOUR GOD!' Button: id: hulk text: "press to smash loki" on_release: root.hulk_smash()
In your python code:
class Marvel(BoxLayout): def hulk_smash(self): self.ids.hulk.text = "hulk: puny god!" self.ids["loki"].text = "loki: >_<!!!" # alternative syntax
When your kv file is parsed, kivy collects all the widgets tagged with id’sand places them in thisself.ids dictionary type property. That means youcan also iterate over these widgets and access them dictionary style:
当你的kv文件被解析后,kivy收集所有带id标签的widgets并放置它们到self.ids字典类型属性当中。这意味着你也可以迭代出这些widgets并连接它们:
for key, val in self.ids.items(): print("key={0}, val={1}".format(key, val))
Note
Although the self.ids method is very concise, it is generally regarded as‘best practice’ to use the ObjectProperty. This creates a direct reference,provides faster access and is more explicit.尽管这很简洁,它通常被认定为使用ObjectProperty的最好练习。这创建了直接的引用,提供更快的连接。
Dynamic Classes¶动态类
Consider the code below:<MyWidget>:Button:
text: "Hello world, watch this text wrap inside the button"
text_size: self.size
font_size: '25sp'
markup: TrueButton:
text: "Even absolute is relative to itself"
text_size: self.size
font_size: '25sp'
markup: TrueButton:
text: "Repeating the same thing over and over in a comp = fail"
text_size: self.size
font_size: '25sp'
markup: TrueButton:
Instead of having to repeat the same values for every button, we can just use atemplate instead, like so:
为了免去重复的赋值动作,我们可以仅仅使用一个模板代替:
<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:
This class, created just by the declaration of this rule, inherits from theButton class and allows us to change default values and create bindings for allits instances without adding any new code on the Python side.
Re-using styles in multiple widgets¶在多个widget中重复使用样式
Consider the code below in my.kv:<MyFirstWidget>: Button: on_press: root.text(txt_inpt.text) TextInput: id: txt_inpt <MySecondWidget>: Button: on_press: root.text(txt_inpt.text) TextInput: id: txt_inpt
In 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
Because both classes share the same .kv style, this design can be simplifiedif we reuse the style for both widgets. You can do this in .kv as follows.In my.kv:
<MyFirstWidget,MySecondWidget>: Button: on_press: root.text(txt_inpt.text) TextInput: id: txt_inpt
By separating the class names with a comma, all the classes listed in thedeclaration will have the same kv properties.
Designing with the Kivy Language¶
One of aims of the Kivy language is toSeparate the concernsof presentation and logic. The presentation (layout) side is addressedby yourkv file and the logic by your py file.
其实就是将layout用kv写,逻辑用python写
The code goes in py files¶
Let’s start with a little example. First, the Python file named main.py:import kivy kivy.require('1.0.5') 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()
In this example, we are creating a Controller class with 2 properties:
infofor receving some text
label_widfor receving the label widget
In addition, we are creating a
do_action()method that will use both ofthese properties. It will change the
infotext and change
text in the
label_widwidget.
The layout goes in controller.kv¶
Executing this application without a corresponding .kv file will work, butnothing will be shown on the screen. This is expected, because theControllerclass has no widgets in it,
it’s just a
FloatLayout. We cancreate the UI around the
Controllerclass in a file namedcontroller.kv,which will be loaded
when we run the
ControllerApp. How this is done andwhat files are loaded is described in the
kivy.app.App.load_kv()
method.
直接执行下面代码,kv文件可以执行,但是没有任何事发生。正如我所料,
因为Controller都没有widgets,它只是个的UI,文件名称为controller.kv,这个文件将在我们运行FloatLayout。我们可以创建一个围绕[code]Controller
ControllerApp时候加载[/code]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #:kivy 1.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' |
BoxLayout. Seems very simple. Thereare 3 things going on here:
Using data from the
Controller. As soon as the
infoproperty ischanged in the controller, the expression
text:'Mycontrollerinfois:'+root.info
will automatically be re-evaluated, changing the textin the
Button.使用来自Controller的data。不久这个在controller里头的info属性将被改变,
text:'Mycontrollerinfois:'+root.info表达式将自动重新赋值,并改变按钮中的text
Giving data to the
Controller. The expression
id:my_custom_labelis assigning the created
Label
the id of
my_custom_label. Then,using
my_custom_labelin the expression
label_wid:my_custom_label
gives the instance of that
Labelwidget to your
Controller.赋予data到Controller。表达式
id:my_custom_label正被表达式中的my_custom_label分配已经创建好的Label。然后,使用[code]label_wid:my_custom_label
my_custom_label赋予Label的widget实例到你的controller。[/code]
Creating a custom callback in the
Buttonusing the
Controller’s
on_pressmethod.在Button创建一个自定义的callback,使用Controller的on_press的方法( 即do_action)
rootand
selfare reserved keywords, useable anywhere.
rootrepresents the top widget in the rule and
selfrepresentsthe
current widget.root和self是内置的键,可以在任何地方使用。root在rulle中代表定层的widget,self代表当前widget。(例如,牛如果修改kv文件中的第12行代码为on_press:self.do_action(),那么会报错:AttributeError: 'Button' object has no attribute 'do_action')
You can use any id declared in the rule the same as
rootand
self. For example, you could do this in the
on_press():你可以使用任何在rule中声明的id,就像使用root、self那样。
Button: on_press: root.do_action(); my_custom_label.font_size = 18
And that’s that. Now when we run main.py, controller.kv will be loaded sothat the
Buttonand
Labelwill
show up and respond to our touch events.
相关文章推荐
- Convert.NET语言代码转换及翻译工具
- Translater-语言翻译类
- 利用开源工具搭一套汉英翻译系统(三):语言模型工具SRILM
- Qt翻译文件结合VS实现语言切换(多语言国际化)
- 语言模型自然语言处理[置顶] 哥伦比亚大学 自然语言处理 公开课 授课讲稿 翻译(四)
- 【翻译】go语言中的map实战
- 谷歌工程师利用和语言翻译类似的技术开发出了一个用于翻译图片主题的机器学习算法
- IBM的云平台Bluemix使用初体验——创建PHP Web 应用程序,添加并使用语言翻译服务
- 【转载】[翻译整理]使用RAPI库操作移动设备——C#语言描述
- 语言术语——英文翻译
- 能自动将软件翻译成不同语言的工具
- 语言翻译程序
- 微软免费图书《Introducing Microsoft LINQ》翻译Chapter3.1-Visual Basic 9.0语言特性
- 重新翻译SciTE的简体中文语言文件
- 国家语言代码大全【方便翻译查询】
- ANTLR(语言识别的另一工具)的简介之三[翻译]
- [Android]简单易用,教你一步实现多国语言翻译
- 搞了一天终于实现了 DataGrid 中的多国语言的问题,采用了中文向其他语言自动翻译的方法,其实不难,主要是想法(本文不涉及这个计算机技术问题,仅以此作为标题)
- Thrift白皮书《Thrift:可扩展的跨语言服务实现》 中文完整翻译
- C++/CLI语言标准草案第8章语言概述节选翻译(8.1-8.2)