Kivy 简明教程
Kivy - Language
本章介绍了 Kivy 设计语言的重要特性、语法和用法。Kivy 语言(也称为“kv”语言)主要描述 Kivy 应用的用户界面。它类似于 Qt 的 QML。在“kv”语言中的规则定义类似于 CSS 规则。
Purpose
Kivy 应用中部件的布局和位置被编码到 Kivy 的 App 类的 build() 方法中。对于具有更简单用户界面的应用程序,这可能很有效。但是,随着布局设计的复杂性增加,它很快变得冗长且难以维护。因此,需要将应用程序的设计部分与其处理逻辑分开。“kv”语言有助于实现此关注分离。
使用“kv”语言脚本,您可以以声明方式创建部件树并将部件属性绑定到回调函数中,这样更自然。以编程方式设计界面的一个缺点是,在应用程序执行之前无法查看外观。另一方面,kviewer 实用程序提供了部件设计和放置的交互式视图,而无需在应用程序中加载该脚本。
Loading the "kv" Script
一旦部件的设计最终确定,便会将其加载到 App 类中。这可以通过两种方式完成。
Using the Naming Convention
将“kv”脚本保存为“.kv”扩展名,其名称与 App 类的名称相对应。如果 App 类名以 app 关键字结尾,则必须省略它。例如,如果像下面那样将 App 类命名为 DemoApp,
Class DemoApp(App):
...
...
然后应该将 kv 文件命名为 demo.kv。Kivy 自动将设计加载到 App 类的 build() 方法中。如果 kv 文件定义了一个根 Widget,它将附加到 App 的 root 属性中并用作应用程序部件树的基础。
Using the Builder Class
如果“kv”文件的文件名不遵循上述约定,则可以使用“kivy.lang”模块中 Loader 类的 load_file() 方法将脚本加载到应用程序中。
from kivy.app import App
from kivy.lang import Builder
Builder.load_file('mykv.kv')
MydemoApp(App):
def build(self):
pass
MydemoApp().run()
还可以将整个“kv”语言脚本作为字符串嵌入到 Python 代码中,并使用 Builder.load_string() 方法将其加载到 App 类中。
from kivy.app import App
from kivy.lang import Builder
kv="""
#kv script goes here
"""
MydemoApp(App):
def build(self):
Builder.load_string(kv)
MydemoApp().run()
“kv”语言具有以下重要元素:
-
Rules -“kv”中的规则类似于 CSS 规则。它适用于继承指定小部件类的特定小部件或类。“kv”规则可以指定交互式行为或使用它们来添加其应用到的 Widget 的图形表示。
-
root Widget - 您可以使用该语言创建整个用户界面。“kv”文件最多只能包含一个根组件。
-
Dynamic Classes - 动态类允许您在不进行任何 Python 声明的情况下即时创建新的部件和规则。
kv 脚本描述了 Widget 的内容。您可以有一个根规则和任意数量的类或模板规则。根规则通过声明根组件的类(没有任何缩进,后跟冒号符号)来声明。它设置 App 实例的根属性。
Widget:
要声明一个类规则,请将 Widget 类的名称放在“<>”中,后跟冒号符号。它定义了该类任何实例的外观和行为 -
<MyWidget>:
Kv 语言规则使用缩进进行分隔,与 Python 源代码相同。要记住的经验法则是:带有角括号的是规则,不带角括号的是根部件。
A schematic example -
<MyClass>:
prop1: value1
prop2: value2
canvas:
CanvasInstruction1:
canvasprop1: value1
CanvasInstruction2:
canvasprop2: value2
AnotherClass:
prop3: value1
“kv”语言有三个特定关键字:
self - 始终引用当前部件。
Button:
text: 'My state is %s' % self.state
root - 引用当前规则中的基部件,并表示该规则的根部件(该规则的第一个实例):
<MyWidget>:
custom: 'Hello world'
Button:
text: root.custom
app - 始终引用您的应用程序实例。
Label:
text: app.name
Kivy 应用程序窗口只能包含一个作为其根对象的小控件。但是,如果你需要将应用程序界面与多个控件组合在一起,则必须使用布局小控件,并将多个 UX 小控件放在其中,然后将布局设置作为应用程序窗口上的根小控件。
下面的“kv”文件脚本定义了一个网格布局,然后可以在 App 类中使用此布局:
GridLayout:
cols:1
Label:
text:'Hello'
font_size:100
color:(1,0,0,1)
Button:
text='Ok'
font_size:100
在上述情况下,Label 组件和 Button 被放置在一个单列 GridLayout 中。然而,不能从 Python 代码中访问对象及其属性。要执行此操作,请在“kv”脚本中定义 id 属性。
GridLayout:
cols:1
Label:
id:l1
text:'Hello'
font_size:60
color:(1,0,0,1)
Button:
id:b1
text='Ok'
font_size:60
当此布局被加载到 build() 方法中时,App 类可以通过此 id 访问部件属性。它有一个 ids 属性,该属性是一个具有 id:值键值对的字典。
print (self.ids.l1.text)
让我们从 kv 脚本开始,如下所示,它在网格布局中包含一个标签和一个按钮:
GridLayout:
cols:1
Label:
text:'Hello'
font_size:60
color:(1,0,0,1)
TextInput:
text:'Hello'
font_size:60
Button:
text:'Ok'
font_size:60
Kivy 应用程序代码加载了上述“kvdemo.kv”脚本:
from kivy.app import App
from kivy.core.window import Window
Window.size = (720,400)
class KvDemoApp(App):
def build(self):
pass
KvDemoApp().run()
让我们在 Kivy 应用程序中添加一个事件处理程序。为了访问小组件属性,我们将 id 属性定义为 label、textinput 和 button。我们在“kv”脚本中定义一个类规则,并在顶部用尖括号将 MyWidget 放进去。
<MyWidget>:
cols:1
size:root.size
Label:
id:l1
text:'Hello'
font_size:60
color:(1,0,0,1)
TextInput:
id:t1
text:'Hello'
font_size:60
Button:
id:b1
text:'Ok'
font_size:60
on_press:root.callback(*args)
请注意,按钮的 on_press 属性绑定到我们将在根类(即 MyWidget 类)中编写的 callback() 方法。
MyWidget 类继承了 GridLayout 小组件。在类内部,提供了一个 callback() 方法。当按钮被按下时,它会将标签标题更新为文本框中输入的文本。
在“kvdemoapp.py”代码中添加以下类:
from kivy.uix.gridlayout import GridLayout
class MyWidget(GridLayout):
def callback(self, *args):
print ("hello")
self.ids.l1.text=self.ids.t1.text
运行程序之后,在文本框中输入一些文本,然后按下按钮。标签上的文本将相应地更改。
我们也可以只在“kv”脚本中提供整个逻辑。我们不需要在 Python 中定义回调。从“kv”代码中使用 label 和 textinput 的 id 属性。
<MyWidget>:
cols:1
size:root.size
Label:
id:l1
text:'Hello'
font_size:60
color:(1,0,0,1)
TextInput:
id:t1
text:'Hello'
font_size:60
Button:
id:b1
text:'Ok'
font_size:60
on_press: l1.text=t1.text
此处,on_press 事件将标签(id 为 l1)文本设置为文本框中的文本,文本框的 id 为“t1”。在 Python 代码端,MyWidget 类将仅有一个 pass 语句。
因此,我们可以看到,“kv”设计语言的使用使得应用程序开发非常方便,因为编程部分和设计部分是分离的。