我有一个问题,可能与模块无关。
在下面的代码中,有一个函数更新,它将通过matplotlib创建一个画布并将其分配给tkinter的相关帧。然后它创建一个事件处理程序Cursor,它应该将鼠标的位置打印到控制台中。但事实并非如此。但是,如果删除方法更新并使用线条在模块正文中创建图形,光标和连接,一切正常。
我错过了什么?我想这是Python的基本知识,可见性和传递正确的实例,我不知道。
import matplotlib.pyplot as plt
from tkinter import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
class Cursor (object):
def __init__ (self, fig):
self.fig = fig
print ("initializing")
def mouse_move (self, event):
if not event.inaxes:
return
x, y = event.xdata, event.ydata
print (x, y)
def connect (self):
print ("Connecting")
self.conmove = self.fig.canvas.mpl_connect ('motion_notify_event', self.mouse_move)
def pyplot_f ():
fig = plt.figure(figsize=(6,4), dpi=100)
axes = fig.add_subplot (111)
axes.plot([1,2,3,4], [1,2,3,4])
Canvas = FigureCanvasTkAgg (fig, master=frame_output)
canvas = Canvas.get_tk_widget()
canvas.grid(row=0,column=0, padx=5, pady=5, sticky="nesw")
return fig
w_width = 1000
w_height = 600
root = Tk()
root.resizable(0,0)
frame_output = Frame (root, bg="", relief=SUNKEN, width=w_width*0.8, height=w_height*0.9)
frame_output.grid(row=0, column=0, padx=20, pady=20, sticky=W+N+E+S)
frame_input = Frame (root, bg="", relief=RAISED,width=w_width*0.2, height=w_height*0.9)
frame_input.grid(row=0, column=1, padx=20, pady=20, sticky=W+N+E+S)
def update ():
fig = pyplot_f()
cursor = Cursor(fig)
cursor.connect()
def on_closing():
print ("Exiting")
root.quit()
update()
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
答案 0 :(得分:2)
您的问题似乎是关于可变范围和生命周期的问题。
当您的update()
函数结束时,其中声明的变量fig
和cursor
超出范围。在update()
中创建的图形和光标对象没有指向它们的进一步引用,因此它们最终被垃圾收集。您的update()
函数已成功创建图形和光标,但不会阻止它们再次被删除。
当您将update()
中的三行移动到模块的主体时,变量fig
和cursor
将保留在范围内,并且在程序之前不会被垃圾收集结束。因此,您的图形和光标已创建,而不是立即进行垃圾回收。
解决此问题的最简单方法是让update()
函数返回游标,然后将其保留在模块范围内:
def update ():
fig = pyplot_f()
cursor = Cursor(fig)
cursor.connect()
return cursor
# ...
cursor = update()
这可以防止游标被垃圾收集,并且由于游标具有对图的引用,因此该图也不会被垃圾收集。