使用 TKinter 在对象内部定义的图像按钮

Use an image-button defined inside an object with TKinter

我正在尝试构建一个 tkinter 按钮,该按钮将图像作为对象内部的背景。为什么第二个实现不起作用没有任何意义!

这里有 3 个非常简单的例子;谁能解释一下为什么第二个实现不起作用?

(Python 3.6.4 :: 巨蟒公司)

1。全局创建的按钮。

很有魅力...

from tkinter import *
from PIL import Image, ImageTk
from numpy import random
w = Tk()
def cb():
    print("Hello World")
image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
b = Button(w, text="text", command=cb, image=image)
b.pack()
w.mainloop()

2。在对象 A 内创建的带有背景图像的按钮

按钮在点击时不起作用,不显示图像:(。显然有问题,但我不明白...

from tkinter import *
from PIL import Image, ImageTk
from numpy import random
w = Tk()
class A():
    def __init__(self, w):
        image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
        b = Button(w, text="text", command=self.cb, image=image)
        b.pack()

    def cb(self):
        print("Hello World")

a = A(w)
w.mainloop()

3。在对象内创建的按钮 A 没有背景图像

按钮正常,但我也想显示图片

from tkinter import *
from PIL import Image, ImageTk
from numpy import random
w = Tk()
class A():
    def __init__(self, w):
        image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
        b = Button(w, text="text", command=self.cb)#, image=image)
        b.pack()

    def cb(self):
        print("Hello World")

a = A(w)
w.mainloop()

我想我明白发生了什么。由于链接的问题,第二种情况发生的是,一旦 __init__ 方法完成,您的 image 就会被垃圾收集。因此,您的图像不再对根应用程序可用,因此无法绑定到它。 解决方法是让它成为class属性:

class A():
    def __init__(self, w):
        self.image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
        b = Button(w, text="text", command=self.cb, image=self.image)
        b.pack()

    def cb(self):
        print("Hello World")

这里有 2 个问题。

第一个问题是__init__后图像没有被保存。您可能知道您需要保存对图像的引用,以便在 tkinter 中使用它。您可能不知道在 class 中,如果您不将图像分配给 class 属性,它将不会在 __init__.

之后保存图像

因此,要解决第一个问题,您需要更改此内容:

image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))

为此:

# add self. to make it a class attribute and keep the reference alive for the image.
self.image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))

您在这里可能没有注意到的第二个问题是在加载图像时您的文字不会显示。这是因为您需要添加参数 compound 以便 tkinter 在按钮中显示图像和文本。也就是说,您还需要更新图像参数以包含新的 self.image.

所以改变这个:

b = Button(w, text="text", command=self.cb, image=image)

为此:

# added compound and change text color so you can see it.
b = Button(w, compound="center" , text="text", fg="white", command=self.cb, image=self.image)

结果: