使用实例属性在tkinter中创建图像

时间:2015-07-31 02:55:30

标签: python oop canvas tkinter

我正在研究一个简单的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()

我有点难过。谁能提供任何有关出错的见解?

1 个答案:

答案 0 :(得分:1)

来自documentation of canvas.create_image() -

  

create_image(position,** options)[#]在画布上绘制图像。

     

image =图像对象。这应该是PhotoImage或BitmapImage,   或兼容的对象(如PIL PhotoImage)。 申请   必须保留对图像对象的引用。

(强调我的)

所以很可能,canvas对象不会保留对图像本身的引用,或者它保留弱引用。在任何一种情况下,简而言之,发生的事情是,在调用canvas.create_image()并且callback()方法结束后,您不再保留对图像对象的任何引用(在create_image()中使用方法),因此没有出现。

在您的情况下,当您在Bacteria课程中保留对图像的引用时,发生的事情是 -

  1. 您正在创建Bacteria对象并加载图像并存储在那里。您只是创建了Bacteria对象 - test_bact - 作为callback()方法的局部变量。

  2. 然后您使用test_bact.imageTk作为image方法的canvas.create_image()参数。

  3. 现在,callback()结束,因此不再引用test_bact,因此会收集垃圾。此外,由于imageTk对象的唯一引用位于Bacteria对象中,因此也会收集垃圾,因此应用程序中不再有对图像对象的引用。

  4. 根据您想要实现的目标,您似乎应该将细菌对象存储为MainWindows类的实例变量。