You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用kv文件的Kivy项目中正确使用self.size?

问题:Kivy纯Python实现图片填满Widget失败,kv实现正常

我尝试用Kivy创建一个图片填满整个Widget的简单应用,使用kv文件实现时一切正常,但改用纯Python代码实现时却无法正常运行:self.size返回值为(100, 100),导致图片仅以100×100的尺寸显示在窗口左下角。

kv文件实现代码

Python代码:

from kivy.app import App
from kivy.uix.widget import Widget


class MainWidget(Widget):
    pass


class MainApp(App):
    def build(self):
        return MainWidget()


MainApp().run()

kv文件内容:

<MainWidget>:
    canvas.before:
        Rectangle:
            source: "background.jpg"
            size: self.size

尝试的纯Python代码

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *


class MainWidget(Widget):
    def __init__(self, **kwargs):
        super(MainWidget, self).__init__(**kwargs)
        with self.canvas.before:
            Rectangle(size = self.size, source = "background.jpg")


class MainApp(App):
    def build(self):
        return MainWidget()


MainApp().run()

这两种实现方式难道不是等价的吗?是什么导致了这种不符合预期的输出?


原因分析

kv语言中的size: self.size是属性绑定,它会建立一种动态关联:当Widget的size属性发生变化时,Rectangle的size会自动同步更新。

而你在Python的__init__方法中直接赋值size=self.size,只是把Widget初始化时的默认尺寸(100,100)这个静态值传给了Rectangle。此时Widget还没有完成布局,真正的窗口尺寸还没生效,后续窗口或Widget尺寸变化时,Rectangle的尺寸不会自动跟进。

纯Python实现的正确写法

方法1:使用属性绑定(推荐,支持实时更新)

通过bind()方法建立Widget的size属性和Rectangle尺寸的联动,确保任何尺寸变化都能同步:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle


class MainWidget(Widget):
    def __init__(self, **kwargs):
        super(MainWidget, self).__init__(**kwargs)
        # 先创建矩形并保存引用
        with self.canvas.before:
            self.bg_rect = Rectangle(source="background.jpg")
        # 绑定size属性,当Widget尺寸变化时调用更新方法
        self.bind(size=self.update_background_size)
        # 初始化时手动调用一次,确保初始尺寸正确
        self.update_background_size()

    def update_background_size(self, *args):
        self.bg_rect.size = self.size


class MainApp(App):
    def build(self):
        return MainWidget()


MainApp().run()

方法2:延迟初始化(仅适配初始布局)

利用Clock.schedule_once延迟执行背景初始化,等Widget完成布局、拿到正确尺寸后再设置Rectangle的大小:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.clock import Clock


class MainWidget(Widget):
    def __init__(self, **kwargs):
        super(MainWidget, self).__init__(**kwargs)
        # 延迟1帧执行,等布局完成
        Clock.schedule_once(self.init_background)

    def init_background(self, dt):
        with self.canvas.before:
            Rectangle(size=self.size, source="background.jpg")


class MainApp(App):
    def build(self):
        return MainWidget()


MainApp().run()

注意:方法2仅在窗口首次打开时设置一次尺寸,如果后续拉伸窗口,图片不会跟着放大;方法1则会实时响应尺寸变化,更符合需求。

内容的提问来源于stack exchange,提问作者Rajdeep Sindhu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:37:44