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

从Tkinter主窗口弹出子窗口显示Matplotlib实时图表失败求助

问题:Tkinter弹出窗口中无法渲染实时Matplotlib图表

主窗口包含「SHOW & SEARCH」按钮,点击后弹出名为「jig status and search」的新窗口,期望在该窗口的图表区域显示实时更新的柱状图,但图表无法正常绘制。

用户提供的代码

from tkinter.ttk import Combobox
from tkinter import *
import pandas as pd
import matplotlib.animation as animation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt

class controller():
    def __init__(self, container,model):
        self.container = container
        self.model=model()
        self.container.title('Jig run count')
        self.container.geometry('280x140')

    def set_up(self):
        self.add_remove_bt.place(x=10, y=50)
        self.count_search_bt = Button(self.container, text='   SHOW & SEARCH  ',
                                      command=self.show_and_search)
        self.count_search_bt.place(x=140, y=50) 

    def show_and_search(self):
        show_and_search_windows=Tk()
        show_and_search_form=Tk.winfo_toplevel(show_and_search_windows)
        show_and_search_form.title("jig status and search")
        show_and_search_form.geometry('800x500')
        self.graph_area=Frame(show_and_search_form,width=450, height=300).place(x=5,y=5)
        self.search_area=Frame(show_and_search_form,width=300, height=300).place(x=460,y=5)
        self.table_area=Frame(show_and_search_form,width=760, height=100).place(x=5,y=310)
        self.fig, self.ax1=plt.subplots()
        self.canvas = FigureCanvasTkAgg(self.fig, self.graph_area)
        ani=animation.FuncAnimation(self.fig,self.plot_chart,interval=1000)
        self.canvas_widget = self.canvas.get_tk_widget()
        self.canvas_widget.pack()

    def plot_chart(self):
        df=pd.read_csv(self.model.df_path,index_col='Type')
        FAT_df=df.loc['FAT'].sort_values(by="running_time",ascending=False)
        print(FAT_df)
        x1=FAT_df['jig_name'].values
        y1=FAT_df['running_time'].values
        print(x1)
        print(y1)
        self.ax1.clear()
        self.ax1.bar(x1,y1,label="top jigs")
        self.ax1.show()

问题修复方案

1. 修正多窗口创建方式

Tkinter中创建子窗口必须使用Toplevel()而非Tk(),Tk()会初始化新的主循环,导致组件交互异常。直接基于主窗口创建Toplevel对象即可:

show_and_search_form = Toplevel(self.container)

2. 修复Frame赋值错误

Frame(...).place(...)返回None,因为place方法无返回值,导致self.graph_area指向空值,画布无法绑定到有效容器。拆分创建与布局步骤:

self.graph_area = Frame(show_and_search_form, width=450, height=300)
self.graph_area.place(x=5, y=5)
# 同理修复其他区域
self.search_area = Frame(show_and_search_form, width=300, height=300)
self.search_area.place(x=460, y=5)
self.table_area = Frame(show_and_search_form, width=760, height=100)
self.table_area.place(x=5, y=310)

3. 正确绑定画布到Frame

将画布的父容器指定为self.graph_area,并使用place布局画布(避免与Frame的place冲突):

self.canvas = FigureCanvasTkAgg(self.fig, master=self.graph_area)
self.canvas_widget = self.canvas.get_tk_widget()
self.canvas_widget.place(x=0, y=0, width=450, height=300)

4. 移除错误的Axes方法

Matplotlib的Axes对象没有show()方法,更新图表后调用self.canvas.draw()刷新画布即可:

# 替换self.ax1.show()
self.canvas.draw()

5. 保留动画对象引用

动画对象若未保存为实例变量,会被Python垃圾回收机制回收,导致动画停止。将ani改为实例属性:

self.ani = animation.FuncAnimation(self.fig, self.plot_chart, interval=1000)

修复后的完整代码

from tkinter.ttk import Combobox
from tkinter import *
import pandas as pd
import matplotlib.animation as animation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt

class Controller():
    def __init__(self, container, model):
        self.container = container
        self.model = model()
        self.container.title('Jig run count')
        self.container.geometry('280x140')
        # 补充原代码未定义的按钮,避免报错
        self.add_remove_bt = Button(self.container, text='ADD/REMOVE')

    def set_up(self):
        self.add_remove_bt.place(x=10, y=50)
        self.count_search_bt = Button(self.container, text='   SHOW & SEARCH  ',
                                      command=self.show_and_search)
        self.count_search_bt.place(x=140, y=50) 

    def show_and_search(self):
        # 使用Toplevel创建子窗口
        show_and_search_form = Toplevel(self.container)
        show_and_search_form.title("jig status and search")
        show_and_search_form.geometry('800x500')
        
        # 拆分Frame创建与布局
        self.graph_area = Frame(show_and_search_form, width=450, height=300)
        self.graph_area.place(x=5, y=5)
        self.search_area = Frame(show_and_search_form, width=300, height=300)
        self.search_area.place(x=460, y=5)
        self.table_area = Frame(show_and_search_form, width=760, height=100)
        self.table_area.place(x=5, y=310)
        
        # 创建Matplotlib画布并绑定到graph_area
        self.fig, self.ax1 = plt.subplots(figsize=(4.5, 3))  # 匹配Frame尺寸
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.graph_area)
        self.canvas_widget = self.canvas.get_tk_widget()
        self.canvas_widget.place(x=0, y=0, width=450, height=300)
        
        # 保存动画引用,防止被回收
        self.ani = animation.FuncAnimation(self.fig, self.plot_chart, interval=1000)

    def plot_chart(self):
        df = pd.read_csv(self.model.df_path, index_col='Type')
        FAT_df = df.loc['FAT'].sort_values(by="running_time", ascending=False)
        x1 = FAT_df['jig_name'].values
        y1 = FAT_df['running_time'].values
        
        self.ax1.clear()
        self.ax1.bar(x1, y1, label="top jigs")
        self.ax1.set_title("Top Jig Running Time")
        self.ax1.legend()
        # 刷新画布
        self.canvas.draw()

# 补充示例Model类,替换为实际业务逻辑
class Model:
    def __init__(self):
        self.df_path = "your_data.csv"  # 替换为实际CSV文件路径

# 启动程序
if __name__ == "__main__":
    root = Tk()
    app = Controller(root, Model)
    app.set_up()
    root.mainloop()

内容的提问来源于stack exchange,提问作者Hoang Minh Nguyen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:00:56