为什么我的tkinter应用程序关闭没有错误消息只有第二次更新命令运行?



我正在制作一个更好的GUI来显示来自某些目录的图像。GUI有一个更新图像的绘图按钮。在功能齐全的GUI中,可以使用各种更改来更新图像,包括图像源,但下面的示例不包括此功能,并且仅绘制相同的图像。plot函数使用matplotlib图和tk画布返回一个可以网格化的对象,以及用于垃圾收集的原始图。

第二次调用plot函数时,GUI关闭,没有任何错误消息。在下面的示例中,在init时使用plot函数,然后在按下按钮时再次使用plot函数。然而,我已经尝试过在init上使用简化的plot函数(如下面的示例所示),并且GUI仅在第二次操作真正的plot函数时关闭。

import tkinter as tk
from PIL import Image, ImageTk
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.figure import Figure 
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg,
NavigationToolbar2Tk)
def plot_image(img_path, root, ratio=2.0):
'''
Plots image using plt.imshow and tk.Canvas

Input:
-img_path: string, filepath to plt.imread-acceptable source
-root: root Tk object for returned widget
-ratio: float, aspect ratio (W:H)
Output:
-tuple: (tkinter Canvas of plt Figure, plt subplot)

Note: plt subplot garbage collection must be handled on application end
'''
# Create image
img = Image.open(img_path)
img_arr = np.asarray(img)

# Create plot
fig = Figure()
base_size = 2.5
fig, plot1 = plt.subplots(1, subplot_kw={'aspect': 'auto'},
figsize=(ratio*base_size, base_size))
xleft, xright = plot1.get_xlim()
ybottom, ytop = plot1.get_ylim()
plot1.set_aspect(abs((xright-xleft)/(ybottom-ytop))*ratio)
plot1.imshow(img_arr, rasterized=True, aspect='auto')
# Return tk.Canvas
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas = canvas.get_tk_widget()
return (canvas, fig)
class UI(tk.Frame):
'''
Frame for displaying a single image
'''
def __init__(self, master, **options):
tk.Frame.__init__(self, master, **options)
self.img_path = "image.png"
self.wgt_img, self.img = plot_image(self.img_path, self)
self.wgt_img.grid(row=0, column=0)
btn_load = tk.Button(self, text="Load",
command=lambda: self.update_image())
btn_load.grid(row=1, column=0)
def update_image(self):
self.wgt_img.grid_forget()
plt.close(self.img)
self.wgt_img, self.img = plot_image(self.img_path, self)
self.wgt_img.grid(row=0, column=0)
def run():
root = tk.Tk()
gui = UI(root)
gui.pack()
root.mainloop()
run()
def load_image(img_path, root):
'''
Plots image using ImageTk.PhotoImage

Input:
-img_path: string, filepath to plt.imread-acceptable source
-root: root Tk object for returned widget
Output:
-tuple: (tkinter Label, tkinter PhotoImage)
'''
img = Image.open(img_path)
img = ImageTk.PhotoImage(img)
return (tk.Label(root, image=img), img)

我试过在函数中添加打印语句。它似乎能够退出该函数,但退出后立即崩溃。在这一点上我有点不知所措。我认为这与使用画布而不是标签有关,但我不知道除此之外。什么好主意吗?

更新

我把它修好了。问题在于画布依赖于现有的图形,因此一旦图形关闭,画布就没有任何东西可以显示,并自行关闭。我不确定为什么没有错误消息,但至少它现在工作。编辑代码:

def update_image(self):
self.wgt_img.destroy()
old_img = self.img
self.wgt_img, self.img = plot_image(self.img_path, self)
plt.close(old_img)
self.wgt_img.grid(row=0, column=0)

相关内容