zoukankan      html  css  js  c++  java
  • 『Python Kivy』Kivy模板语言KV说明

    语言概念

    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对MySQL数据库操作
    使用Python对SQLite数据库操作
    使用Python对Access读写操作
    使用Python对Excel进行读写操作
    C# Serialization performance in System.Runtime.Serialization.Formatters.Binary.BinaryFormatter,Newtonsoft.Json.JsonConvert and System.Text.Json.JsonSerializer.Serialize
    C# calculate disk size
    C# rename files
    C# copy files from source directory to destination file and rename repeated files and does not override
    C# event
    C# redis StackExchange
  • 原文地址:https://www.cnblogs.com/sitemanager/p/4119058.html
Copyright © 2011-2022 走看看