如何在Tkinter中实现滚动条内多图表垂直堆叠展示?
在Tkinter中垂直堆叠带滚动条的Matplotlib图表,或无滚动条放置多图表的方案
一、解决滚动条中垂直堆叠图表的问题
你的代码存在两个关键问题导致图表无法垂直堆叠:
- 图表部件的布局方向错误:
build_graph中使用side=tk.LEFT会让图表横向排列,需改为垂直方向布局。 - 新增图表后未更新滚动区域:每次添加新图表后,Canvas的滚动范围不会自动更新,需手动触发。
修改后的完整代码如下,关键改动已标注:
# importing tkinter gui import tkinter as tk from tkinter import * import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # import functions def build_graph(root): figure3 = plt.Figure(figsize=(5, 4), dpi=100) ax3 = figure3.add_subplot(111) x = [i for i in range(100)] points = [i for i in range(100)] ax3.plot(x, points, color='b') scatter3 = FigureCanvasTkAgg(figure3, root) # 改动1:改为垂直堆叠布局,fill=tk.X适配容器宽度,pady增加间距 scatter3.get_tk_widget().pack(side=tk.TOP, fill=tk.X, pady=5) ax3.legend(['average voltage difference']) ax3.set_xlabel('measurement points') ax3.set_ylabel('voltage(V)') ax3.set_title('Chart') # 改动2:更新Canvas滚动区域,确保滚动条识别新增内容 root.update_idletasks() my_canvas.config(scrollregion=my_canvas.bbox(ALL)) # creating window window = tk.Tk() # getting screen width and height of display width = window.winfo_screenwidth() height = window.winfo_screenheight() # setting tkinter window size window.geometry("%dx%d" % (width, height)) window.title("Interface") label = tk.Label(window, bg='lightblue', text="charts") # creating a label label.pack() # showing label # Create A Main frame top_frame = Frame(master=window) # making an empty container for properties, buttons and fields top_frame.pack(fill=BOTH,expand=1, side=TOP) # what is fill, expand, side? # Create Frame for X Scrollbar top_frame_first = LabelFrame(top_frame, text="Properties") top_frame_first.pack(fill=X,side=TOP) # making a new field frames_number_label = Label(top_frame_first, bg='lightblue', text="enter frames quantity") frames_number_label.pack(side = LEFT) frames_number_box = Entry(top_frame_first, width=5) frames_number_box.insert(0, "1") frames_number_box.pack(side = LEFT) path_label = Label(top_frame_first, bg='lightblue', text="write path to file") path_label.pack(side=LEFT) path_box = Entry(top_frame_first) path_box.insert(0, 'experimental.txt') path_box.pack(side=LEFT) # Create A Main frame main_frame = Frame(window) main_frame.pack(fill=BOTH,expand=1) # Create Frame for X Scrollbar sec = Frame(main_frame) sec.pack(fill=X,side=BOTTOM) # Create A Canvas my_canvas = Canvas(main_frame) my_canvas.pack(side=LEFT,fill=BOTH,expand=1) # # Add A Scrollbars to Canvas y_scrollbar = Scrollbar(main_frame,orient=VERTICAL,command=my_canvas.yview) y_scrollbar.pack(side=RIGHT,fill=Y) # Configure the canvas my_canvas.configure(yscrollcommand=y_scrollbar.set) my_canvas.bind("<Configure>",lambda e: my_canvas.config(scrollregion= my_canvas.bbox(ALL))) # Create Another Frame INSIDE the Canvas second_frame = Frame(my_canvas) # Add that New Frame a Window In The Canvas my_canvas.create_window((0,0),window= second_frame, anchor="nw") # 移除无用的未使用组件 # listbox = Listbox() # vertical scrollbar # scrollbar = Scrollbar(orient="vertical", command = listbox.yview) def build(): # 支持根据输入数量批量创建图表 count = int(frames_number_box.get()) for _ in range(count): build_graph(second_frame) main_button = Button(top_frame, text="Calculate", width=15, height=3) main_button.config(command=build) main_button.pack() window.mainloop() # showing main window
关键改动说明:
- 调整图表部件的
pack参数为side=tk.TOP, fill=tk.X,实现垂直堆叠并适配容器宽度 - 在
build_graph末尾添加滚动区域更新逻辑,确保Canvas能识别新增内容后的高度变化 - 优化
build函数,支持根据输入框数值批量创建图表 - 删除代码中未使用的
listbox和多余滚动条定义
二、无滚动条放置最多20个图表的替代方案
如果不想使用滚动条,以下两种方案更实用:
- Notebook标签页:每个图表放在独立标签页中,用户通过切换标签查看内容,适合需要独立查看单图表的场景,是20个图表的最优选择。
- 网格自动换行布局:用
grid布局设置固定列数(如4列),让图表自动横向填充后换行,仅适合高分辨率大屏场景。
Notebook标签页示例代码片段
# 需额外导入ttk模块 from tkinter import ttk # 创建Notebook组件替换原有Canvas布局 main_frame = Frame(window) main_frame.pack(fill=BOTH, expand=1) notebook = ttk.Notebook(main_frame) notebook.pack(fill=BOTH, expand=1) # 修改build_graph函数,将图表添加到新标签页 def build_graph(notebook): figure3 = plt.Figure(figsize=(5, 4), dpi=100) ax3 = figure3.add_subplot(111) x = [i for i in range(100)] points = [i for i in range(100)] ax3.plot(x, points, color='b') # 创建标签页容器 tab_frame = Frame(notebook) scatter3 = FigureCanvasTkAgg(figure3, tab_frame) scatter3.get_tk_widget().pack(fill=BOTH, expand=1) # 添加新标签页 notebook.add(tab_frame, text=f"Chart {notebook.index('end')+1}") # 修改build函数 def build(): count = int(frames_number_box.get()) for _ in range(count): build_graph(notebook)
这种方式无需滚动条,用户可快速切换查看任意图表,体验优于滚动大量图表。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

