2016-10-08 25 views
1

我有一個問題,甚至可能與模塊無關。Matplotlib和它與tkinter的連接

在下面的代碼中,有一個函數更新,它將通過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() 

回答

2

您的問題似乎是一個關於變量範圍和生命週期。

當您的update()函數結束時,其中聲明的變量figcursor超出範圍。您的update()中創建的圖形和光標對象沒有指向它們的其他參考,因此它們最終被垃圾收集。您的update()函數正在成功創建圖形和光標,但並不妨礙它們再次被刪除。

當您將update()內的三條線移動到模塊主體時,變量figcursor將保持在範圍內,並且在程序結束之前不會被垃圾收集。因此你的數字和光標被創建,而不是立即垃圾收集。

解決這一問題是用於update()函數返回光標,然後保留在模塊範圍的最簡單方法:

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

# ... 

cursor = update() 

這防止了光標被當作垃圾收集,並且當光標具有對該圖的引用,該圖也不會被垃圾收集。

+0

謝謝!但它不會解決問題。我有一個按鈕應該調用更新函數,這將創建一個新的佈局,因此我需要重新創建光標。在按鈕的情況下,光標將被銷燬 – EvilAnton

+0

好的,問題確實在範圍之內。我找到了解決辦法。我稍微改了一個類,現在它鏈接到方法connect中的圖形。 __init__方法保持空(通過)。我在主模塊中創建了一個Cursor實例,因此它總是存在並且不被GC收集。 – EvilAnton