我正在研究一个简单的tkinter程序,并且我正在尝试创建一个回调函数来获取图像(使用PIL导入并存储为类属性)并在画布上绘制它单击相应的按钮。每次单击都应创建一个新的Bacteria对象,通过在画布上创建新图像来反映(在实际程序中,新对象也会附加到数组中,稍后在程序的执行中使用 - 代码这是一种简化的方法。)
以下运行没有错误(除了用于发布的假文件名引起的文件未找到错误),但遗憾的是,单击按钮时画布上没有绘制图像。当导入图像并将其存储为MainWindow类的属性时,代码按预期工作 - 当导入/存储为Bacteria类的属性时,它似乎只会失败。
import tkinter as tk
import random
from PIL import Image
from PIL import ImageTk
class MainWindow(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent, background = "white")
self.pack()
self.canvas_height = 500
self.canvas_width = 1000
self.canvas = tk.Canvas(self, height = self.canvas_height, width = self.canvas_width)
self.canvas.grid(row = 0, column = 0)
self.launch_button = tk.Button(self, text = "Haz clic!", width = 25, command = self.callback)
self.launch_button.grid(row = 1, column = 0, sticky = "W")
def callback(self):
test_bact = Bacteria()
x_pos = random.randint(0,1000)
y_pos = random.randint(0,500)
self.canvas.create_image(x_pos, y_pos, image = test_bact.imageTk)
class Bacteria:
def __init__(self):
self.image = Image.open('testBacterium.png')
self.imageTk = ImageTk.PhotoImage(image=self.image)
root = tk.Tk()
app = MainWindow(root)
app.mainloop()
我有点难过。谁能提供任何有关出错的见解?
答案 0 :(得分:1)
来自documentation of canvas.create_image()
-
create_image(position,** options)[#]在画布上绘制图像。
image =图像对象。这应该是PhotoImage或BitmapImage, 或兼容的对象(如PIL PhotoImage)。 申请 必须保留对图像对象的引用。
(强调我的)
所以很可能,canvas对象不会保留对图像本身的引用,或者它保留弱引用。在任何一种情况下,简而言之,发生的事情是,在调用canvas.create_image()
并且callback()
方法结束后,您不再保留对图像对象的任何引用(在create_image()
中使用方法),因此没有出现。
在您的情况下,当您在Bacteria
课程中保留对图像的引用时,发生的事情是 -
您正在创建Bacteria对象并加载图像并存储在那里。您只是创建了Bacteria对象 - test_bact
- 作为callback()
方法的局部变量。
然后您使用test_bact.imageTk
作为image
方法的canvas.create_image()
参数。
现在,callback()
结束,因此不再引用test_bact
,因此会收集垃圾。此外,由于imageTk
对象的唯一引用位于Bacteria对象中,因此也会收集垃圾,因此应用程序中不再有对图像对象的引用。
根据您想要实现的目标,您似乎应该将细菌对象存储为MainWindows
类的实例变量。