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

Kivy中Widget在Layout内显示位置异常问题求助

问题描述

我在S2中绘制了一个方框,本应显示在S2(即右侧中间区域),但它却出现在屏幕左下角(100,100)位置。是否是我在属性赋值上出现了错误?

相关代码:

class R(Widget):
    def __init__(self,x,y,szer,wys, kB=(1, 1, 1, 1)):
        self.x=x
        self.y=y
        self.szer=szer
        self.wys=wys
        super().__init__()
        with self.canvas:
            Color(*kB)
            Line(rectangle=(self.x,self.y,self.szer,self.wys),width=1.5)



Okno = BoxLayout(orientation='vertical', spacing=10)

Top = BoxLayout(orientation='horizontal', spacing=10,size_hint=(1, .35))
F.CustomGraphics.SetBG(Top, bg_color=[0,1,0,0.2])
Top.add_widget(Label(text="aaaaa"))

Srodek = BoxLayout(orientation='horizontal', spacing=10)  

S1 = BoxLayout(orientation='vertical', spacing=10)
F.CustomGraphics.SetBG(S1, bg_color=[1,0,0,0.2])
S1.add_widget(Label(text="bb 11"))
Srodek.add_widget(S1)

S2 = BoxLayout(orientation='vertical', spacing=10)
F.CustomGraphics.SetBG(S2, bg_color=[1,1,0,0.2])
S2.add_widget(F.R(100,100,100,100, kB=Ziel50))
Srodek.add_widget(S2)

Bottom = BoxLayout(orientation='horizontal', spacing=10,size_hint=(1, .35))
F.CustomGraphics.SetBG(Bottom, bg_color=[0,0,1,0.2])
Bottom.add_widget(Label(text="cccc"))
            
Okno.add_widget(Top)
Okno.add_widget(Srodek)
Okno.add_widget(Bottom)

self.add_widget(Okno)

这个绿色方框本应显示在其他位置。

问题原因

问题出在自定义Widget的画布绘制逻辑和属性处理上:

  1. Kivy中Widget的画布默认使用全局屏幕坐标系,你直接用self.x、self.y绘制矩形,这个坐标是相对于屏幕原点(左下角)的,而非S2容器的局部坐标系。
  2. 直接给self.x、self.y赋值,没有使用Kivy的Property属性系统,导致Widget无法和布局系统联动,布局容器也无法管理它的位置。
  3. 自定义的R组件未设置size_hint或固定大小,布局容器无法正确计算它的尺寸和位置。
解决方案

修改R类,让绘制基于Widget自身的局部坐标系,并通过Kivy属性系统与布局联动:

方案1:绘制Widget内部填充矩形

如果需要让矩形占满Widget的整个区域:

from kivy.uix.widget import Widget
from kivy.graphics import Color, Line
from kivy.properties import ListProperty

class R(Widget):
    # 用Kivy属性定义颜色,支持动态更新
    kB = ListProperty((1, 1, 1, 1))

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 绑定属性变化时自动更新画布
        self.bind(pos=self.update_canvas, size=self.update_canvas, kB=self.update_canvas)
        self.update_canvas()

    def update_canvas(self, *args):
        self.canvas.clear()
        with self.canvas:
            Color(*self.kB)
            # 基于Widget自身坐标系绘制((0,0)是Widget的左下角)
            Line(rectangle=(0, 0, self.size[0], self.size[1]), width=1.5)

添加到S2时,指定固定大小避免布局压缩:

# 设置固定宽高,size_hint设为None让布局不自动缩放
S2.add_widget(F.R(size=(100,100), size_hint=(None, None), kB=Ziel50))

方案2:支持自定义偏移的内部矩形

如果需要让矩形在Widget内部有偏移:

from kivy.uix.widget import Widget
from kivy.graphics import Color, Line, PushMatrix, Translate
from kivy.properties import NumericProperty, ListProperty

class R(Widget):
    x_offset = NumericProperty(0)
    y_offset = NumericProperty(0)
    rect_width = NumericProperty(100)
    rect_height = NumericProperty(100)
    kB = ListProperty((1, 1, 1, 1))

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.bind(pos=self.update_canvas, size=self.update_canvas,
                  x_offset=self.update_canvas, y_offset=self.update_canvas,
                  rect_width=self.update_canvas, rect_height=self.update_canvas,
                  kB=self.update_canvas)
        self.update_canvas()

    def update_canvas(self, *args):
        self.canvas.clear()
        with self.canvas:
            # 切换到Widget自身的局部坐标系
            PushMatrix()
            Translate(self.pos[0], self.pos[1])
            Color(*self.kB)
            Line(rectangle=(self.x_offset, self.y_offset, self.rect_width, self.rect_height), width=1.5)

使用示例:

S2.add_widget(F.R(x_offset=50, y_offset=50, rect_width=100, rect_height=100,
                  size=(200,200), size_hint=(None, None), kB=Ziel50))

修改后,矩形会显示在S2容器内部的对应位置,而非屏幕左下角。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:30:01