Matplotlib画布绑定Tkinter框架后点击事件无法触发,求原因
Let's break down why your onclick function isn't triggering, and fix it step by step:
The Core Issues
Your Matplotlib canvas isn't actually being displayed in
frame1
You created theFigureCanvasTkAggobject, but never added its underlying Tkinter widget to yourparent1frame. Right now, you're clicking empty space inframe1, not the Matplotlib plot—so no event fires.Local variable garbage collection
Yourfigandcanvasvariables are local to theplot()method. Once that method finishes running, Python might clean them up, which breaks the event connection entirely.
Fixed Code
Here's the adjusted version with comments pointing out key changes:
import Tkinter as tk import ttk from matplotlib.backends.backend_tkagg import ( FigureCanvasTkAgg, NavigationToolbar2TkAgg) import matplotlib.pyplot as plt import numpy as np class Frame_examples_program(): def __init__(self): self.window = tk.Tk() self.window.title("Amazing GUI 5000") # Configure main window grid to let frames expand properly self.window.grid_rowconfigure(0, weight=1) self.window.grid_rowconfigure(1, weight=0) self.window.grid_columnconfigure(0, weight=1) self.create_widgets() def create_widgets(self): self.window['padx'] = 10 self.window['pady'] = 10 frame1 = ttk.Frame(self.window, relief=tk.RIDGE) frame1.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S, padx=0, pady=0) # Configure frame1 grid to let the canvas fill available space frame1.grid_rowconfigure(0, weight=1) frame1.grid_columnconfigure(0, weight=1) frame2 = ttk.Frame(self.window, relief=tk.RIDGE) frame2.grid(row=1, column=0, sticky=tk.E + tk.W + tk.N + tk.S, padx=0, pady=0) self.plot_frame = PlotFrame(frame1, frame2) class PlotFrame(): def __init__(self, parent1, parent2): self.parent1 = parent1 self.parent2 = parent2 # Store canvas as instance attribute to avoid garbage collection self.canvas = self.plot() self.plot_toolbar(self.canvas) def plot(self): # Store fig/ax as instance attributes to keep them in memory self.fig, self.ax = plt.subplots() self.ax.imshow(np.ones((100,100)), picker=True) canvas = FigureCanvasTkAgg(self.fig, self.parent1) # Add the canvas widget to parent1 frame so it's visible canvas.get_tk_widget().grid(row=0, column=0, sticky=tk.NSEW) # Connect the click event to our handler canvas.mpl_connect('button_press_event', self.onclick) return canvas def plot_toolbar(self, canvas): toolbar = NavigationToolbar2TkAgg(canvas, self.parent2) toolbar.update() canvas.draw() def onclick(self, event): # Optional: print click coordinates for debugging print(f'Clicked at x={event.xdata}, y={event.ydata}') print('WOHOOOO') program = Frame_examples_program() program.window.mainloop()
Key Fixes Explained
- Grid configuration: We added
weightvalues to the main window andframe1grids, so the plot canvas expands to fill the available space instead of staying tiny. - Instance attributes for plot objects: By storing
self.fig,self.ax, andself.canvas, we ensure Python doesn't garbage-collect these objects after theplot()method finishes running. - Proper canvas placement: The line
canvas.get_tk_widget().grid(...)ensures the plot is actually rendered insideframe1, so clicks register with Matplotlib instead of hitting empty space. - Cleaned up toolbar code: Removed the misplaced canvas repositioning call in
plot_toolbarthat was causing confusion.
Now when you click the plot, your onclick function will fire immediately and print "WOHOOOO" (plus click coordinates if you keep that debug line)!
内容的提问来源于stack exchange,提问作者Sebastiano1991

