如何在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()
问题截图

解决方案
问题根源
- Rectangle未绑定Widget属性:KV里的
Rectangle没有指定pos和size,默认用(0,0)位置和(10,10)尺寸,所以只显示左下角小方块。 - KV语法错误:Widget最后两行
pos: self.pos和size: self.size属于无效位置,应该删除。 - 更新逻辑未触发:
update_labels方法没被Clock调度,不会执行更新操作。 - 代码缺失依赖:原代码缺少
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()
关键修改说明
- 绑定Rectangle属性:在KV的
Rectangle里添加pos: self.pos和size: self.size,让矩形完全跟随Widget的位置和尺寸。 - 触发更新逻辑:用
Clock.schedule_interval定时调用update_labels,实现动态修改进度条宽度。 - 补充缺失依赖:添加必要的导入和类定义,确保代码能正常运行。
- 优化进度控制:通过修改Widget的
size属性,自动同步到Rectangle,实现Python控制宽度的需求。
内容的提问来源于stack exchange,提问作者Asterlux
相关产品推荐
相关产品推荐

