【问题标题】:Using instance attributes to create images in tkinter使用实例属性在 tkinter 中创建图像
【发布时间】:2015-10-22 14:42:29
【问题描述】:

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

我对此感到有些困惑。任何人都可以就出了什么问题提供任何见解吗?

【问题讨论】:

  • test_bact 是函数本地的,垃圾收集也是如此,当然类中的所有内容也会消失。使用 self.test_bact 使其在函数返回后保留。

标签: python oop canvas tkinter


【解决方案1】:

来自documentation of canvas.create_image() -

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

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

(强调我的)

所以很可能,画布对象不保留对图像本身的引用,或者它保留弱引用。无论哪种情况,简而言之,在调用 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 对象中,它也会被垃圾回收,因此您的应用程序中不再有对图像对象的引用。


从您想要实现的目标来看,您似乎应该将细菌对象存储为MainWindows 类的实例变量。

【讨论】:

  • 感谢您的解释!完全阐明了我对画布如何工作的想法。
猜你喜欢
  • 2023-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多