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

如何在Kivy的FloatLayout中绘制可动态调整宽度的矩形?

问题:Kivy中在FloatLayout绘制可Python控制宽度的矩形进度条失败

完全不理解Kivy框架,看了大量教程和示例后,还是没法完成在kv界面绘制矩形的简单任务。一直遵循Kivy文档推荐的「kv语言处理图形、Python处理逻辑」开发思路。

需要在现有界面上绘制绿色矩形作为进度条,理想状态下通过Python代码控制其宽度展示事件进度,但始终无法实现。无论怎么设置,矩形只显示在屏幕左下角的小方块,没法调整位置与大小,而且目前无法通过Python代码控制其尺寸。

请帮忙理解如何在FloatLayout界面中添加矩形,并实现通过Python代码修改其宽度?附上相关精简代码及问题截图。

KV代码

<RS_Dock_Screen>:
    name: 'rs_dock'
    FloatLayout:
        id:dock_layout
        Image:
            source: f'{root.mimic_directory}/Mimic/Pi/imgs/russian/ROSdockBackground.png'
            fit_mode: "fill"
        Label:
            id: ros_mode
            pos_hint: {"center_x": 0.33, "center_y": 0.73}
            text: '-'
            font_size: 16
            text_size: 300,None
            halign: 'left'
            markup: True
            color: root.signalcolor
        Widget:
            id: docking_bar
            #size_hint: 0.5,0.5
            #pos_hint: {'center_x':0.6,'center_y':0.6}
            #pos: 800 * 0.53, 600 * 0.205
            #size: 800 * 0.325, 600 * 0.04
            pos: 400,400
            size: 600,10
            canvas.after:
                Color:
                    rgba: 0, 1, 0, 0.5
                Rectangle:
            pos: self.pos
            size: self.size

Python代码

from kivy.app import App
from kivy.lang import Builder
from kivy.network.urlrequest import UrlRequest #using this to request webpages
from kivy.clock import Clock
from kivy.event import EventDispatcher
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen, SwapTransition, NoTransition
from kivy.uix.popup import Popup
from kivy.uix.label import Label

mimic_data_directory = Path.home() / '.mimic_data'
mimic_directory = op.abspath(op.join(__file__, op.pardir, op.pardir, op.pardir))

class MainScreen(Screen):
    mimic_directory = op.abspath(op.join(__file__, op.pardir, op.pardir, op.pardir))
    

class RS_Dock_Screen(Screen, EventDispatcher):
    mimic_directory = op.abspath(op.join(__file__, op.pardir, op.pardir, op.pardir))
    signalcolor = ObjectProperty([1, 1, 1])

class MainScreenManager(ScreenManager):
    mimic_directory = op.abspath(op.join(__file__, op.pardir, op.pardir, op.pardir))


class MainApp(App):
    mimic_directory = op.abspath(op.join(__file__, op.pardir, op.pardir, op.pardir))
    ros_data = []

    def build(self):
        global startup, ScreenList, stopAnimation

        self.main_screen = MainScreen(name = 'main')
        self.rs_dock = RS_Dock_Screen(name='rs_dock')
        self.rs_eva = EVA_RS_Screen(name='rs_eva')
        self.rs_screen = RS_Screen(name='rs')

        root = MainScreenManager(transition=NoTransition())
        root.add_widget(self.main_screen)
        root.add_widget(self.rs_dock)
        root.add_widget(self.rs_eva)
        root.add_widget(self.rs_screen)

        root.current = 'main' #change this back to main when done with eva setup
        return root

    def update_labels(self, dt):
        value = 1
        #self.rs_dock.update_progress(value)
        print(self.rs_dock.ids.dock_layout.width)
        #self.rs_dock.ids.docking_bar.size = (self.rs_dock.ids.dock_layout.width * value * 0.325, self.rs_dock.ids.dock_layout.height * 0.04)


#All GUI Screens are on separate kv files
Builder.load_file(mimic_directory + '/Mimic/Pi/Screens/MainScreen.kv')
Builder.load_file(mimic_directory + '/Mimic/Pi/Screens/RS_Dock_Screen.kv')
Builder.load_string('''
#:kivy 1.8
#:import kivy kivy
#:import win kivy.core.window
ScreenManager:
    MainScreen:
    RS_Dock_Screen:

''')

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

问题截图

仅显示在左下角的小矩形


解决方案

问题根源

  1. Rectangle未绑定Widget属性:KV里的Rectangle没有指定pos和size,默认用(0,0)位置和(10,10)尺寸,所以只显示左下角小方块。
  2. KV语法错误:Widget最后两行pos: self.pos和size: self.size属于无效位置,应该删除。
  3. 更新逻辑未触发:update_labels方法没被Clock调度,不会执行更新操作。
  4. 代码缺失依赖:原代码缺少Path、os导入,以及EVA_RS_Screen、RS_Screen类定义,运行会报错。

修正后的完整代码

KV代码(RS_Dock_Screen.kv)

<RS_Dock_Screen>:
    name: 'rs_dock'
    FloatLayout:
        id:dock_layout
        Image:
            source: f'{root.mimic_directory}/Mimic/Pi/imgs/russian/ROSdockBackground.png'
            fit_mode: "fill"
        Label:
            id: ros_mode
            pos_hint: {"center_x": 0.33, "center_y": 0.73}
            text: '-'
            font_size: 16
            text_size: 300,None
            halign: 'left'
            markup: True
            color: root.signalcolor
        Widget:
            id: docking_bar
            pos: 400,400
            size: 600,10
            canvas.after:
                Color:
                    rgba: 0, 1, 0, 0.5
                Rectangle:
                    pos: self.pos
                    size: self.size

Python代码

from kivy.app import App
from kivy.lang import Builder
from kivy.network.urlrequest import UrlRequest
from kivy.clock import Clock
from kivy.event import EventDispatcher
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from pathlib import Path
import os as op

mimic_data_directory = Path.home() / '.mimic_data'
mimic_directory = op.abspath(op.join(__file__, op.pardir, op.pardir, op.pardir))

class MainScreen(Screen):
    mimic_directory = mimic_directory

class RS_Dock_Screen(Screen, EventDispatcher):
    mimic_directory = mimic_directory
    signalcolor = ObjectProperty([1, 1, 1])

class EVA_RS_Screen(Screen):
    pass

class RS_Screen(Screen):
    pass

class MainScreenManager(ScreenManager):
    mimic_directory = mimic_directory

class MainApp(App):
    mimic_directory = mimic_directory
    ros_data = []

    def build(self):
        self.main_screen = MainScreen(name = 'main')
        self.rs_dock = RS_Dock_Screen(name='rs_dock')
        self.rs_eva = EVA_RS_Screen(name='rs_eva')
        self.rs_screen = RS_Screen(name='rs')

        root = MainScreenManager(transition=NoTransition())
        root.add_widget(self.main_screen)
        root.add_widget(self.rs_dock)
        root.add_widget(self.rs_eva)
        root.add_widget(self.rs_screen)

        root.current = 'rs_dock'  # 直接切换到目标界面测试
        Clock.schedule_interval(self.update_labels, 0.5)  # 每0.5秒更新一次进度
        return root

    def update_labels(self, dt):
        # 模拟进度值,0到1之间循环变化
        current_width = self.rs_dock.ids.docking_bar.size[0]
        max_width = self.rs_dock.ids.dock_layout.width * 0.325
        new_width = current_width + 20 if current_width < max_width else 0
        self.rs_dock.ids.docking_bar.size = (new_width, self.rs_dock.ids.dock_layout.height * 0.04)

Builder.load_file(mimic_directory + '/Mimic/Pi/Screens/MainScreen.kv')
Builder.load_file(mimic_directory + '/Mimic/Pi/Screens/RS_Dock_Screen.kv')
Builder.load_string('''
#:kivy 1.8
ScreenManager:
    MainScreen:
    RS_Dock_Screen:
''')

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

关键修改说明

  1. 绑定Rectangle属性:在KV的Rectangle里添加pos: self.pos和size: self.size,让矩形完全跟随Widget的位置和尺寸。
  2. 触发更新逻辑:用Clock.schedule_interval定时调用update_labels,实现动态修改进度条宽度。
  3. 补充缺失依赖:添加必要的导入和类定义,确保代码能正常运行。
  4. 优化进度控制:通过修改Widget的size属性,自动同步到Rectangle,实现Python控制宽度的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 12:57:33