如何拆分需访问kv文件的Python类,实现可导入且不重复加载kv?
问题原因
你当前的报错核心有两个:
Builder.load_file("b.kv")语句和类写在同一个文件,每次导入该文件时都会自动执行加载逻辑,导致kv重复加载- RightSide类内部硬编码依赖全局的
kv变量访问ids,拆分后跨文件无法读取这个全局变量
具体修改步骤
1. 拆分文件结构
把RightSide类单独存放到right_side.py文件中,移除该文件内所有全局的kv加载代码,相关依赖同步导入到该文件即可。
2. 解耦类内部的ids访问逻辑
删除类中对全局kv变量的引用,改用Kivy自带的运行时App实例获取根控件,修改后的类代码如下:
from kivy.uix.boxlayout import BoxLayout from kivy.properties import StringProperty from kivy.app import App # 按需导入你项目中的其他依赖,比如Skeleton、menu、parameter_length、数据库驱动等 from your_project import Skeleton, menu, parameter_length import mysql.connector as sql # 全局变量也可以移到主App类中管理,耦合度更低 OID = 0 query = "你的实际SQL插入语句" class RightSide(BoxLayout): order_size = [] overlay = StringProperty('Current Order will be displayed here') tabname = parameter_length iterator = 0 def __init__(self, **kwargs): super().__init__(**kwargs) self.orientation = 'vertical' for i in range(len(menu)): self.add_widget(Skeleton()) def tally(self): global OID order_size = self.order_size OID += 1 # 直接从当前运行的App拿根控件,不需要依赖全局kv变量 rightside = App.get_running_app().root.ids.one.two.three.newlay.rightside for skel in rightside.children: if isinstance(skel, Skeleton): if self.iterator > len(menu)-1: self.iterator = 0 order_size.clear() self.tabname[self.iterator] = skel.drink_name, skel.ids.label_id.text self.iterator += 1 order_size.insert(0, skel.ids.label_id.text) order_size.insert(0, OID) self.tabname.reverse() self.tabname.insert(0, OID) self.overlay = ''.join(map(str, self.tabname)) # 数据库操作部分保持不变即可 con = sql.connect(host='xxxxxx', user='root', password='xxxxxxx.', database='new_schema') cur = con.cursor() cur.execute(query, order_size) con.commit() con.close() def clean(self): rightside = App.get_running_app().root.ids.one.two.three.newlay.rightside for skel in rightside.children: if isinstance(skel, Skeleton): skel.ids.label_id.text = '0' skel.count = 0
3. 主文件统一加载kv
kv加载逻辑仅保留在主入口文件中,避免重复加载,主文件示例代码:
from kivy.app import App from kivy.lang import Builder # 导入拆分后的RightSide类 from right_side import RightSide # 只在主入口加载一次kv,还可以加判断彻底避免重复加载 if not Builder.has_file("b.kv"): kv_root = Builder.load_file("b.kv") class MainApp(App): # 也可以把OID等全局变量放到这里管理 # OID = 0 def build(self): return kv_root if __name__ == "__main__": MainApp().run()
额外优化建议
- kv文件中的自定义控件规则不需要修改,只要保证类导入路径正确即可正常识别
- 全局变量尽量放到App类中管理,不要用global关键字,需要访问时调用
App.get_running_app().变量名即可 - 如果类的逻辑只需要操作自身子控件,也可以直接用
self.ids访问,不需要获取全局根控件
内容的提问来源于stack exchange,提问作者ChrisCross
相关产品推荐
相关产品推荐

