【问题标题】:Matplotlib and it's connection with tkinterMatplotlib 及其与 tkinter 的连接
【发布时间】:2016-10-08 11:26:54
【问题描述】:

我有一个问题,可能与模块无关。

在下面的代码中,有一个函数更新,它将通过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()

【问题讨论】:

    标签: python matplotlib tkinter


    【解决方案1】:

    您的问题似乎与变量范围和生命周期有关。

    当您的update() 函数结束时,其中声明的变量figcursor 将超出范围。在您的update() 中创建的图形和光标对象没有指向它们的进一步引用,因此它们最终被垃圾收集。您的 update() 函数已成功创建图形和光标,但不会阻止它们再次被删除。

    当您将update() 中的三行移动到模块主体时,变量figcursor 将保留在范围内,并且在程序结束之前不会被垃圾回收。因此,您的图形和光标被创建,而不是立即被垃圾收集。

    解决此问题的最简单方法是让 update() 函数返回光标,然后将其保留在模块范围内:

    def update ():
        fig = pyplot_f()
        cursor = Cursor(fig)
        cursor.connect()
        return cursor
    
    # ...
    
    cursor = update()
    

    这可以防止光标被垃圾回收,并且由于光标引用了图形,因此图形也不会被垃圾回收。

    【讨论】:

    • 谢谢!但是,它不会解决问题。我有一个按钮,它应该调用一个更新函数,它将创建一个新的布局,因此我需要重新创建光标。在有按钮的情况下,光标将被销毁
    • 好的,问题确实在范围内。我找到了解决方法。我稍微改变了类,现在它链接到方法connect中的图。 init 方法保持为空(通过)。我在主模块中创建了一个 Cursor 的实例,因此它始终存在并且不会被 GC 收集。
    猜你喜欢
    • 2012-11-11
    • 2016-06-14
    • 2013-09-17
    • 2020-09-21
    • 2013-10-29
    • 2016-06-20
    • 2015-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多