Kivy的KV语言总结

Kivy的KV语言总结

    • [🔍 **三种规则的终极对比表**](#🔍 三种规则的终极对比表)
    • [💡 **一句话区分**`仅仅是一种区分含义,都是可以实例化的`](#💡 一句话区分仅仅是一种区分含义,都是可以实例化的)
    • [💡 **属性和id绑定 **](#💡 **属性和id绑定 **)
    • [📝 **完整示例:一个登录界面**](#📝 完整示例:一个登录界面)
    • [🎯 **规则影响范围的可视化**](#🎯 规则影响范围的可视化)
    • [🔧 **Python代码配合**](#🔧 Python代码配合)
    • [🚨 **关键点再强调**](#🚨 关键点再强调)
    • [🚨 **案例界面展示**](#🚨 案例界面展示)

说实在的,KV语言说的不明不白,官网解释一团糟

🔍 三种规则的终极对比表

规则类型 写法 什么时候用 作用 类比
根规则 Button: Label: MyWidget: 在应用中需要实际显示这个控件 创建具体的控件实例 就像在餐厅点一份具体的菜
类规则 <Button>: <Label>: <MyWidget>: 想要改变某一类控件的默认外观(所有该类控件都变) 修改已有类的默认样式 就像改变餐厅菜单上某道菜的默认做法(所有点这道菜的人都受影响)
动态类规则 <MyButton@Button>: <BigLabel@Label>: 想要创建一个新类型的控件,基于现有控件但有自己的样式 创建一个继承自现有类的新类 就像创建一道新菜,基于现有菜但有自己的特色

💡 一句话区分 仅仅是一种区分含义,都是可以实例化的

  • 根规则Button: → "我要一个按钮"
  • 类规则<Button>: → "所有按钮都应该长这样"
  • 动态类规则<MyButton@Button>: → "我发明了一种新按钮叫MyButton"

💡 **属性和id绑定 **

  • 使用ids访问不太好,把id和property绑定起来,这样代码就可以用property代替id访问控件了。

📝 完整示例:一个登录界面

kv 复制代码
# kvlang.kv - 完整的KV文件示例

# ============================================
# 1. 动态类规则:创建自定义样式的控件(新类型)
# ============================================
<Label>
    color: (0, 1, 0, 1)

<ErrorLabel@Label>:           # 创建一种"新标签"叫ErrorLabel
    opacity: 0.5              # 初始
    font_size: '14sp'
    bold: True

<StyledButton@Button>:          # 创建一种"新按钮"叫StyledButton
    background_color: (0.2, 0.6, 1, 1)
    color: (1, 1, 1, 1)
    font_size: '16sp'
    size_hint: (None, None)
    size: (200, 50)
    border_radius: [10]


# ============================================
# 2. 类规则:修改所有TextInput的默认样式
# ============================================
<TextInput>:                    # 影响文件中所有的TextInput
    size_hint: (None, None)
    size: (300, 60)
    padding: [10, 10]
    background_color: (0.95, 0.95, 0.95, 1)
    foreground_color: (0, 0, 0, 1)

# ============================================
# 3. 根规则:创建实际的界面布局
# ============================================
<MyScreen@BoxLayout>:                      # 这是应用的根控件
    # 关键代码在这里 
    # 将Python属性绑定到KV的id,
    # KV中的 my_label: lbl_id 就是告诉Kivy:把Python里的my_label属性和KV里叫lbl_id的控件连接起来。
    # 并且注意这种用法只能在自定义的类规则内部,即绑定必须在自定义类的规则内。
    # 不一定属性的名称和值必须一样。
    my_label: lbl_id    

    orientation: 'vertical'
    padding: 40
    spacing: 20
    # 1. 背景层
    canvas.before:
        # 渐变背景
        Color:
            rgba: (0.5, 0.5, 0.5, 1)
        Rectangle:
            pos: self.pos
            size: self.size
    
    Label:                      # 根规则:创建一个具体的标签
        text: "用户登录"
        font_size: '24sp'
        size_hint_y: None
        height: 50

    ErrorLabel:                 # 根规则:使用动态类创建的错误标签实例
        id: error_label
        text: "ErrorLabel"                # 初始为空
        
    
    TextInput:                  # 根规则:创建一个具体的输入框(自动应用上面的类规则)
        id: username_input
        hint_text: "用户名"
    
    TextInput:                  # 另一个输入框(也自动应用类规则)
        id: password_input
        hint_text: "密码"
        password: True          # 密码模式
    
    StyledButton:               # 根规则:使用动态类创建的按钮实例
        text: "登录"
        on_press: app.login(username_input.text, password_input.text)
    
    Button:                     # 根规则:普通的按钮(不受上面的动态类影响)
        text: "注册"
        background_color: (0.4, 0.8, 0.4, 1)  # 绿色
        size_hint: (None, None)
        size: (150, 40)


  
    Label:
        id: lbl_id        # 定义id
        text: "初始文本"
    Button:
        text: "点击我(查看id和属性绑定的案例)"
        on_press: root.change_text_by_property()  # 调用Python方法
    Label:
        id: raw_id        # 定义id
        text: "初始文本"
    Button:
        text: "点击我(查看id和ids的案例)"
        on_press: root.change_text_by_ids()  # 调用Python方法

🎯 规则影响范围的可视化

复制代码
整个KV文件
├── 动态类规则:<StyledButton@Button>:
│   └── 影响:所有使用 `StyledButton:` 的地方
│
├── 类规则:<TextInput>:
│   └── 影响:文件中所有 `TextInput:` 的地方
│
└── 根规则:BoxLayout:(根控件)
    ├── Label:(普通标签)
    ├── TextInput:(自动应用类规则样式)
    ├── TextInput:(自动应用类规则样式)
    ├── ErrorLabel:(应用动态类样式)
    ├── StyledButton:(应用动态类样式)
    └── Button:(普通按钮,不受类规则影响)

🔧 Python代码配合

python 复制代码
'''
- 三种规则说明
- kv中的id和python中的ids
    - python中的ids是`<class 'kivy.properties.ObservableDict'>`类型,如:
    {'error_label': <WeakProxy to <kivy.factory.ErrorLabel object at 0x000001870FADCBB0>>, 'username_input': <WeakProxy to <kivy.uix.textinput.TextInput object at 0x000001870FB07930>>, 'password_input': <WeakProxy to <kivy.uix.textinput.TextInput object at 0x000001871B924360>>}
    - 

 - 属性和id绑定
   - 使用ids访问不太好,把id和property绑定起来,这样代码就可以用property代替id访问控件了。



'''

from reg_font import register_font
register_font()

from kivy.app import App

from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty  # 导入Property
# 自定义的根控件类
class MyScreen(BoxLayout):
    # 1. 定义ObjectProperty
    my_label = ObjectProperty(None)
    # 只用id的方式
    def change_text_by_ids(self):
        # 必须通过ids字典
        self.ids.raw_id.text = "按钮被点击了!"
        
    # 用Property的方式  
    def change_text_by_property(self):
        # 直接通过属性访问
        print(type(self.my_label))
        print(self.my_label)
        self.my_label.text = "按钮被点击了!"
class KvLangApp(App):
    def build(self):
        return MyScreen()
    
    def login(self, username, password):
        # 获取KV中创建的控件
        root = self.root
        error_label = root.ids.error_label
        print(root)
        print(type(root)) # <class '__main__.MyScreen'>

        # {
        #  'error_label': <WeakProxy to <kivy.factory.ErrorLabel object at 0x00000194D4B84DE0>>,
        #  'username_input': <WeakProxy to <kivy.uix.textinput.TextInput object at 0x00000194D4BA3B60>>,
        #  'password_input': <WeakProxy to <kivy.uix.textinput.TextInput object at 0x00000194E09C4590>>, 
        #  'lbl_id': <WeakProxy to <kivy.uix.label.Label object at 0x00000194E09F1B70>>, 
        #  'raw_id': <WeakProxy to <kivy.uix.label.Label object at 0x00000194E0A06F90>>
        # }

        print(root.ids)
        print(type(root.ids)) # <class 'kivy.properties.ObservableDict'>
        
        if not username or not password:
            error_label.text = "用户名和密码不能为空"
            error_label.opacity = 1  # 显示错误信息
        else:
            error_label.opacity = 0  # 隐藏错误信息
            print(f"尝试登录: {username}")



if __name__ == '__main__':
    KvLangApp().run()

🚨 关键点再强调

  1. 动态类规则是"发明"

    kv 复制代码
    <MyButton@Button>:   # 发明了MyButton这种按钮
    <RedLabel@Label>:    # 发明了RedLabel这种标签

    之后才能用MyButton:RedLabel:来创建实例。

  2. 类规则是"修改默认"

    kv 复制代码
    <Button>:    # 修改所有Button的默认样式
    <Label>:     # 修改所有Label的默认样式

    影响文件中所有该类控件。

  3. 根规则是"实际创建"

    kv 复制代码
    Button:      # 创建一个具体的按钮
    MyButton:    # 创建一个动态类的实例

    这是实际会显示在屏幕上的东西。

🚨 案例界面展示


相关推荐
代码猎人2 分钟前
substring和substr有什么区别
前端
pimkle2 分钟前
visactor vTable 在移动端支持 ellipsis 气泡
前端
donecoding2 分钟前
告别 scrollIntoView 的“越级滚动”:一行代码解决横向滚动问题
前端·javascript
0__O2 分钟前
如何在 monaco 中实现自定义语言的高亮
前端·javascript·编程语言
Jasmine_llq4 分钟前
《P3200 [HNOI2009] 有趣的数列》
java·前端·算法·线性筛法(欧拉筛)·快速幂算法(二进制幂)·勒让德定理(质因子次数统计)·组合数的质因子分解取模法
呆头鸭L5 分钟前
快速上手Electron
前端·javascript·electron
Aliex_git9 分钟前
性能指标笔记
前端·笔记·性能优化
秋天的一阵风9 分钟前
🌟 藏在 Vue3 源码里的 “二进制艺术”:位运算如何让代码又快又省内存?
前端·vue.js·面试
松涛和鸣10 分钟前
48、MQTT 3.1.1
linux·前端·网络·数据库·tcp/ip·html
helloworld也报错?11 分钟前
保存网页为PDF
前端·javascript·pdf