『Python Kivy』Kivy模板语言KV说明

摘要:
语言概念KV语言允许您以声明方式创建控件树,并将控件属性绑定到其他控件或使用自然方式进行回调。您也可以使用kv语言处理事件。将它们视为类级变量,只能在KV语言中使用Python中的Button:id:hulktext:“presstosmashloki”on_release:root.hulk_Smash():解析KV文件后,Kivy使用id收集所有控制标记并将其放入self.ids字典中。
语言概念

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’

免责声明:文章转载自《『Python Kivy』Kivy模板语言KV说明》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇『WPF』实现拖动文件到窗体(控件)『Python Kivy』API说明:kivy.app.App下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

走进WPF之UI布局

一个成功的软件,离不开人性化的UI设计,如何抓住用户第一视觉,让用户产生依赖感,合适优雅的布局必不可少。本文以一些简单的小例子,简述WPF中布局面板控件的使用,仅供学习分享使用,如有不足之处,还请指正。 涉及知识点 在WPF中,关于布局面板控件,主要有以下几种: StackPanel:栈面板,可以将元素排列成一行或者一列。其特点是:每个元素各占一行或者一列...

UI基础 视图控制器

RootViewController #import "RootViewController.h" #import "SecondViewController.h" @interfaceRootViewController () @end @implementationRootViewController - (void)viewDidLoad {...

超炫的Button按钮展开弧形动画效果

----------------------收藏备用 ------------------------------- 代码下载:http://download.csdn.net/detail/qq263229365/5622693 今天从网上看到一个这样的效果,感觉很有创意,自己也搜集了一些资料,仿照着实现了一下。 下面就直接上源码: 首先看一下...

大作业:电梯设计的概要设计文档

一、系统硬件接口定义 1.电梯内外操作按钮与显示屏幕 电梯内部的操作界面包括楼层按钮、对应的指示灯、开关门按钮(紧急呼叫按钮)以及显示当前楼层数的屏幕。按钮有向指示灯和CPU传输的接口,屏幕有接受CPU传输的接口。 每个楼层的操作界面包括上行与下行按钮、对应指示灯以及显示两台电梯楼层数和运行状态的屏幕。每层楼的行程开关通过CPU将电梯运行信息传输给屏幕,按钮...

vue 和 react语法对比异同点

vue 和 react 学习 异同点 本文不做两个框架比较,只对比了两个框架的语法对比,不代表任何观点,盗版必究,本人唯一qq:421217189 欢迎大家一起来学习探讨,壮我大前端(本文markdown直接生成,没有排版,也是为了防止那些不要脸的直接复制我文章的人,在此特声明,所有直接窃取文化知识的人,本人必将追究法律责任,本人qq:421217189,新...

使用CSplitterWnd分割窗口 一 二部分(读此文章实验成功)

使用CSplitterWnd分割窗口(一) 一、基本的CSplitterWnd的使用 1. 在CMainFrame中添加一个CSplitterWnd成员:CSplitterWnd m_splitterwnd1; 2.基于CView创建两个新的视图类,CViewLeft和CViewRight,一个用于在左边显示,一个用于在右边显示。 3.重载CMai...