Kivy调用Matplotlib绘图后Screen页面切换失效、报错问题求助
问题原因
你代码的核心错误是覆盖了Kivy控件内置的canvas属性:
- Kivy所有可视化控件都自带内置的
canvas属性,用于自身的图形绘制,类型是kivy.graphics.instructions.Instruction - 你把Matplotlib生成的画布直接赋值给
self.canvas,覆盖了原有属性,页面切换时Kivy读取canvas属性绘制界面时类型不匹配,就会触发你遇到的TypeError - 同时原有界面绘制逻辑被破坏,就会出现两个页面内容重叠的问题
修复方案
1. 修改变量名(核心修复)
把Python代码里Matplotlib画布的变量名从self.canvas改成不冲突的名称,比如self.mpl_canvas
2. 补充KV文件的语法错误
原KV文件中<SecondScreen>定义后缺少冒号,补上即可
3. 可选优化
每次生成直方图前先清空容器内的旧控件,避免重复添加多个画布导致内存占用过高
修改后可运行代码
Python代码
from kivy.app import App from kivy.uix.button import Button from kivy.config import Config from kivy.uix.gridlayout import GridLayout from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.lang import Builder from kivy.uix.screenmanager import ScreenManager, Screen from kivy.core.window import Window from kivy.clock import Clock import random import matplotlib matplotlib.use('module://kivy.garden.matplotlib.backend_kivy') from matplotlib import pyplot as plt class ScreenManagement(ScreenManager): pass class MainScreen(Screen): def __init__(self,**kwargs): super(MainScreen, self).__init__(**kwargs) Clock.schedule_once(self.show_hist) def show_hist(self, *args): self.toPlot = random.sample(range(1, 36), 30) self.fig = plt.figure() self.ax = self.fig.add_subplot(111) self.ax.set_xlabel('Score', fontsize=30) self.ax.set_ylabel('Frequency', fontsize=30) self.ax.set_title('Histogram of scores',fontsize=30) plt.xticks(fontsize=30) plt.yticks(fontsize=30) self.binsize = 36 self.h = self.ax.hist(self.toPlot, self.binsize) # 这里修改变量名,不要和内置canvas重名 self.mpl_canvas = self.fig.canvas # 清空容器内旧内容,避免重复添加 self.hist2show.clear_widgets() self.hist2show.add_widget(self.mpl_canvas) class SecondScreen(Screen): def __init__(self,**kwargs): super(SecondScreen, self).__init__(**kwargs) # 加载kv文件 presentation = Builder.load_file("demo_kivy.kv") class normApp(App): Window.clearcolor = (1, 1, 1, 1) def build(self): return presentation if __name__ == '__main__': normApp().run()
KV文件(demo_kivy.kv)
ScreenManagement: MainScreen: name: "MainScreen" id: main_screen SecondScreen: name: "SecondScreen" id: second_screen <MainScreen>: name: "MainScreen" hist2show:hist2show GridLayout: cols:2 rows:3 BoxLayout: id: hist2show color: 0, 0, 1, 1 background_color: 0.2, 0.2, 0.2, 0.2 Button: text: "Next screen" color: 0, 0, 0, 1 background_color: 0.2, 0.2, 0.2, 0.2 on_release: app.root.current = "SecondScreen" <SecondScreen>: name: "SecondScreen" Button: text: "Go back to the first screen" color: 0, 0, 0, 1 background_color: 0.2, 0.2, 0.2, 0.2 on_release: app.root.current = "MainScreen"
内容的提问来源于stack exchange,提问作者Dawid Archibald
相关产品推荐
相关产品推荐

