如何基于Kivy中另一个控件类调整当前控件的尺寸?
修复Kivy控件尺寸复用的循环依赖问题
问题原因
你遇到的超长报错栈是因为循环属性绑定:在KButton2的BaseButtonSize中,你设置width: self.width*1.25,但BaseButtonSize的size已经绑定了Window.width*0.0441作为宽度。这会形成无限循环:width依赖自身计算后的值,而size又依赖width,Kivy的属性系统会不断触发更新,最终导致栈溢出。
直接修复方案
修改Kv代码,避免在BaseButtonSize内部修改自身的width,而是在KButton2层直接基于基础尺寸计算目标尺寸:
from kivy.uix.button import Button from kivy.uix.relativelayout import RelativeLayout from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder Builder.load_string(""" #:import Window kivy.core.window.Window <ViewPort>: KButton1: KButton2: <BaseButtonSize>: size_hint: None,None size: Window.width*0.0441,Window.height*0.147 <KButton1>: size_hint: None,None size: button.size BaseButtonSize: id: button <KButton2>: size_hint: None,None # 直接基于基础按钮的宽度乘以系数,而非修改基础按钮自身宽度 size: button.width * 1.25, button.height BaseButtonSize: id: button """) class BaseButtonSize(Button): pass class KButton1(RelativeLayout): pass class KButton2(RelativeLayout): pass class ViewPort(BoxLayout): pass if __name__=="__main__": from kivy.app import App class TestApp(App): def build(self): return ViewPort() TestApp().run()
更优实现方式:尺寸逻辑复用(而非嵌套控件)
你当前的方案通过嵌套BaseButtonSize控件来复用尺寸,其实没必要——嵌套控件会增加布局层级,且容易引发绑定问题。更简洁的方式是抽离尺寸配置逻辑,让按钮直接复用:
方式1:Kv语言定义全局尺寸变量
直接在Kv中定义基础尺寸变量,所有按钮直接引用并调整系数:
from kivy.uix.button import Button from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder Builder.load_string(""" #:import Window kivy.core.window.Window #:set base_btn_width Window.width*0.0441 #:set base_btn_height Window.height*0.147 <ViewPort>: KButton1: KButton2: <KButton1>: size_hint: None, None size: base_btn_width, base_btn_height <KButton2>: size_hint: None, None size: base_btn_width*1.25, base_btn_height """) class KButton1(Button): pass class KButton2(Button): pass class ViewPort(BoxLayout): pass if __name__=="__main__": from kivy.app import App class TestApp(App): def build(self): return ViewPort() TestApp().run()
方式2:用Mixin类复用尺寸逻辑
如果需要支持窗口大小变化时自动更新尺寸,可以用Mixin类封装基础尺寸计算:
from kivy.uix.button import Button from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder from kivy.properties import NumericProperty class BaseButtonMixin: base_width = NumericProperty(0) base_height = NumericProperty(0) def __init__(self, **kwargs): super().__init__(**kwargs) from kivy.core.window import Window self._update_base_size(Window) # 监听窗口尺寸变化,自动更新基础尺寸 Window.bind(width=self._update_base_size, height=self._update_base_size) def _update_base_size(self, window, *args): self.base_width = window.width * 0.0441 self.base_height = window.height * 0.147 class KButton1(BaseButtonMixin, Button): def __init__(self, **kwargs): super().__init__(**kwargs) self.size_hint = (None, None) # 绑定尺寸到基础属性 self.bind(base_width=self._update_size, base_height=self._update_size) def _update_size(self, *args): self.size = (self.base_width, self.base_height) class KButton2(BaseButtonMixin, Button): def __init__(self, **kwargs): super().__init__(**kwargs) self.size_hint = (None, None) self.bind(base_width=self._update_size, base_height=self._update_size) def _update_size(self, *args): self.size = (self.base_width * 1.25, self.base_height) Builder.load_string(""" <ViewPort>: KButton1: KButton2: """) class ViewPort(BoxLayout): pass if __name__=="__main__": from kivy.app import App class TestApp(App): def build(self): return ViewPort() TestApp().run()
这种方式既实现了尺寸逻辑复用,又能自动响应窗口大小变化,布局层级也更简洁。
内容的提问来源于stack exchange,提问作者Ten Kho
相关产品推荐
相关产品推荐

