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

如何为含Matplotlib图表的Tkinter Canvas添加可用滚动条?

问题描述

我尝试为Tkinter的Canvas添加滚动条,以查看无法适配屏幕或Canvas分配空间的Matplotlib图表集合。此前我已实现为标签、按钮添加滚动条的功能,但该方法对图表无效。以下是我编写的示例代码,其中绘制了包含2个堆叠子图的大型图表,但滚动条无法正常工作,恳请各位提供帮助。

import tkinter as tk
from tkinter import ttk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.pyplot as plt

class Example(tk.Tk):
    
    def __init__(self,*args,**kwargs):
        tk.Tk.__init__(self,*args,**kwargs)
        
                 
        tk.Button(self,bg='red',text="one").grid(row=0,column=0,sticky='we', padx=5, pady=10)
        
        tk.Button(self,bg='blue',text="two").grid(row=1,column=0,ipadx=200,sticky='we', padx=5, pady=5)
        
        tk.Label(self,bg='green',text="label").grid(row=2,column=0,sticky='we',padx=5, pady=5)
        
        
        first_frame= tk.Frame(self, pady=5, padx=5)
        first_frame.grid(row=3,column=0)
               
        canvas=tk.Canvas(first_frame,bg="orange",height=300,width=480)
        canvas.pack(side="bottom", fill="both", expand=True)
        
        scrollbar = ttk.Scrollbar(canvas, orient="vertical", command=canvas.yview)
        scrollbar.pack(side="right", fill="y")
        
        canvas.configure(yscrollcommand=scrollbar.set)
               
        scrollbar.bind("<Configure>",lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
        
        second_frame=tk.Canvas(canvas)
      
        canvas.create_window((0, 0), window=second_frame, anchor="ne")

       
        # Random data
        np.random.seed(3)
        x = 0.5 + np.arange(8)
        y = np.random.uniform(2, 7, len(x))
        

        # Plot 2 stacked figures
        fig, ax1= plt.subplots(2,figsize=(5,50))
        
        ax1[0].step(x, y, linewidth=2.5)
        
        ax1[0].set(xlim=(0, 8), xticks=np.arange(1, 8),
                ylim=(0, 8), yticks=np.arange(1, 8))
        
        ax1[1].step(x, y, linewidth=2.5)
        
        ax1[1].set(xlim=(0, 8), xticks=np.arange(1, 8),
                ylim=(0, 8), yticks=np.arange(1, 8))
        
        # Draw into canvas
        canvas_fig = FigureCanvasTkAgg(fig,canvas)        
        canvas_fig.get_tk_widget().pack(side="bottom", fill="y")        
        scrollbar.config(command=canvas_fig.get_tk_widget().yview)   
        
        

app=Example()
app.geometry("480x320")
app.title("Scrollfigure")

app.mainloop()
解决方案

你的代码存在几处关键问题导致滚动条失效,修改后的代码如下:

import tkinter as tk
from tkinter import ttk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt

class Example(tk.Tk):
    
    def __init__(self,*args,**kwargs):
        tk.Tk.__init__(self,*args,**kwargs)
        
        tk.Button(self,bg='red',text="one").grid(row=0,column=0,sticky='we', padx=5, pady=10)
        tk.Button(self,bg='blue',text="two").grid(row=1,column=0,ipadx=200,sticky='we', padx=5, pady=5)
        tk.Label(self,bg='green',text="label").grid(row=2,column=0,sticky='we',padx=5, pady=5)
        
        first_frame= tk.Frame(self, pady=5, padx=5)
        first_frame.grid(row=3,column=0, sticky='we')
        
        # 滚动Canvas
        canvas=tk.Canvas(first_frame,bg="orange",height=300,width=480)
        canvas.pack(side="left", fill="both", expand=True)
        
        # 滚动条
        scrollbar = ttk.Scrollbar(first_frame, orient="vertical", command=canvas.yview)
        scrollbar.pack(side="right", fill="y")
        
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # 中间容器,用来承载Matplotlib图表
        inner_frame = tk.Frame(canvas)
        canvas.create_window((0, 0), window=inner_frame, anchor="nw")
        
        # 绑定容器的配置事件,更新滚动区域
        def update_scrollregion(event):
            canvas.configure(scrollregion=canvas.bbox("all"))
        inner_frame.bind("<Configure>", update_scrollregion)
        
        # 生成数据和图表
        np.random.seed(3)
        x = 0.5 + np.arange(8)
        y = np.random.uniform(2, 7, len(x))
        
        fig, ax1= plt.subplots(2,figsize=(5,10))  # 调整figsize避免过于庞大
        ax1[0].step(x, y, linewidth=2.5)
        ax1[0].set(xlim=(0, 8), xticks=np.arange(1, 8),
                ylim=(0, 8), yticks=np.arange(1, 8))
        ax1[1].step(x, y, linewidth=2.5)
        ax1[1].set(xlim=(0, 8), xticks=np.arange(1, 8),
                ylim=(0, 8), yticks=np.arange(1, 8))
        
        # 将Matplotlib画布放入中间容器
        canvas_fig = FigureCanvasTkAgg(fig, inner_frame)        
        canvas_fig.get_tk_widget().pack(side="top", fill="both", expand=True)
        
        # 可选:添加Matplotlib导航工具栏
        toolbar = NavigationToolbar2Tk(canvas_fig, inner_frame)
        toolbar.update()
        canvas_fig.get_tk_widget().pack(side="top", fill="both", expand=True)

app=Example()
app.geometry("480x320")
app.title("Scrollfigure")
app.mainloop()

关键修改点说明

  • 新增中间容器:创建inner_frame作为承载Matplotlib图表的容器,再将该容器添加到滚动Canvas中,确保滚动区域能正确识别图表的完整尺寸
  • 修正滚动区域绑定:将<Configure>事件绑定到inner_frame,当容器大小变化时自动更新滚动Canvas的scrollregion
  • 调整滚动条绑定:滚动条的命令关联到滚动Canvas的yview,同时滚动Canvas的yscrollcommand关联滚动条,形成双向联动
  • 调整图表父容器:将Matplotlib画布的父容器设置为inner_frame,而非直接绑定到滚动Canvas
  • 优化图表尺寸:适当调整figsize避免图表过于庞大,提升滚动体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:54:27