为何Kivy布局画布绘制的线条会短暂显示后消失?
Kivy绘制线条短暂显示后消失的原因及解决方法
问题描述
点击按钮在布局画布上绘制线条,但线条短暂显示后就消失了。
相关代码
KV语言代码
#:import Window kivy.core.window.Window MDScreenManager: BigScreen: <BigScreen>: name: "page" # layout holding cards MDFloatLayout: id: game_layout pos_hint: {'center_x': .5, 'center_y': .5} size_hint: None, None size: Window.width, Window.height md_bg_color: "black" MDIconButton: id: hint icon: "language-python" pos_hint: {"center_x": .5, "y": .9} theme_icon_color: "Custom" icon_color: "orange" md_bg_color: "white" on_release: app.draw_line()
Python代码
class BigScreen(MDScreen): pass class DrawingApp(MDApp): def build(self): return Builder.load_string(kv) def draw_line(self): game_layout = self.root.get_screen("page").ids.game_layout with game_layout.canvas: Line( points = [0, 0, 700, 1000], width = 10, color = (1, 0, 0), ) if __name__ == '__main__': DrawingApp().run()
原因分析
- 画布重绘机制:Kivy布局的
canvas属于静态绘制层,每次布局触发重绘(比如窗口调整、组件状态变化)时,会清空原有内容并重新渲染,临时添加的Line指令不会被持久化保存。 - 垃圾回收:创建的
Line对象没有被任何变量引用,Python的垃圾回收机制会在短时间内回收这个对象,导致线条从画布上消失。
解决方法
方法一:保存线条引用并使用canvas.after
通过实例变量保存绘制的线条对象,同时将线条添加到canvas.after层(确保线条绘制在布局内容之上):
修改后的Python代码:
from kivy.graphics import Line from kivy.uix.screenmanager import MDScreen from kivymd.app import MDApp from kivy.lang import Builder kv = """ #:import Window kivy.core.window.Window MDScreenManager: BigScreen: <BigScreen>: name: "page" MDFloatLayout: id: game_layout pos_hint: {'center_x': .5, 'center_y': .5} size_hint: None, None size: Window.width, Window.height md_bg_color: "black" MDIconButton: id: hint icon: "language-python" pos_hint: {"center_x": .5, "y": .9} theme_icon_color: "Custom" icon_color: "orange" md_bg_color: "white" on_release: app.draw_line() """ class BigScreen(MDScreen): pass class DrawingApp(MDApp): def __init__(self, **kwargs): super().__init__(**kwargs) self.drawn_lines = [] # 保存线条引用,避免被垃圾回收 def build(self): return Builder.load_string(kv) def draw_line(self): game_layout = self.root.get_screen("page").ids.game_layout line = Line(points=[0, 0, 700, 1000], width=10, color=(1, 0, 0)) game_layout.canvas.after.add(line) self.drawn_lines.append(line) if __name__ == '__main__': DrawingApp().run()
方法二:使用独立的绘制Widget
创建一个专门用于绘制的Widget,所有动态绘制内容都添加到这个Widget的画布上,避免布局重绘时丢失内容:
修改后的代码:
from kivy.graphics import Line from kivy.uix.widget import Widget from kivy.uix.screenmanager import MDScreen from kivymd.app import MDApp from kivy.lang import Builder kv = """ #:import Window kivy.core.window.Window MDScreenManager: BigScreen: <BigScreen>: name: "page" MDFloatLayout: id: game_layout pos_hint: {'center_x': .5, 'center_y': .5} size_hint: None, None size: Window.width, Window.height md_bg_color: "black" DrawingWidget: id: drawing_canvas size: game_layout.size pos: game_layout.pos MDIconButton: id: hint icon: "language-python" pos_hint: {"center_x": .5, "y": .9} theme_icon_color: "Custom" icon_color: "orange" md_bg_color: "white" on_release: app.draw_line() """ class DrawingWidget(Widget): pass class BigScreen(MDScreen): pass class DrawingApp(MDApp): def build(self): return Builder.load_string(kv) def draw_line(self): drawing_canvas = self.root.get_screen("page").ids.drawing_canvas with drawing_canvas.canvas: Line(points=[0, 0, 700, 1000], width=10, color=(1, 0, 0)) if __name__ == '__main__': DrawingApp().run()
内容的提问来源于stack exchange,提问作者Timson
相关产品推荐
相关产品推荐

