Python 使用TKinter对象中定义的图像按钮

Python 使用TKinter对象中定义的图像按钮,python,tkinter,python-imaging-library,tk,Python,Tkinter,Python Imaging Library,Tk,我正在尝试构建一个对象内以图像为背景的tkinter按钮。为什么第二个实现不起作用,这毫无意义 这里有3个非常简单的例子;谁能解释第二次实施不起作用的原因 (Python 3.6.4::Anaconda,Inc.) 1.全局创建的按钮。 工作起来很有魅力 from tkinter import * from PIL import Image, ImageTk from numpy import random w = Tk() def cb(): print("Hello World")

我正在尝试构建一个对象内以图像为背景的
tkinter
按钮。为什么第二个实现不起作用,这毫无意义

这里有3个非常简单的例子;谁能解释第二次实施不起作用的原因

(Python 3.6.4::Anaconda,Inc.)

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()

我想我理解发生了什么。由于链接的问题,在第二种情况下发生的事情是,
\uuuu init\uuuu
方法完成后,您的
图像将被垃圾收集。因此,您的图像对于根应用程序不再可用,因此无法绑定到它。
解决方法是将其设置为类属性:

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")

这里有两个问题

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

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

image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
b = Button(w, text="text", command=self.cb, image=image)
为此:

# 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))))
# 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)
您可能没有注意到的第二个问题是,在加载图像时文本将不会显示。这是因为您需要添加参数
composite
,以便tkinter在按钮中同时显示图像和文本。也就是说,您还需要更新图像参数以包含新的
self.image

因此,改变这一点:

image = ImageTk.PhotoImage(image=Image.fromarray(random.random((50,50))))
b = Button(w, text="text", command=self.cb, image=image)
为此:

# 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))))
# 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)
结果:


确实很棘手……如果你在类外声明你的
图像,它就可以工作了……也许这个问题会有帮助……但是如果你把它作为类变量,它就可以工作了……简单的答案是你需要在按钮上添加一个特殊的参数,告诉它同时使用图像和文本。
复合
。然后将
图像
更改为
>self.image
@toti08确实……实际上,它在
PhotoImage
@toti08的文档中只是为了澄清你的意思是类属性。变量是他们现在使用的。类属性是我们用
self.
创建的。这将纠正图像问题,但不显示文本。因此这不是一个完整的解决方案对于第二块和第三块代码的问题。@Mike SMT在原始问题中,问题在于图像和按钮的功能。老实说,我没有检查按钮中显示的文本…操作说明按钮工作正常,但我也希望显示图像,因此我认为操作是蚂蚁同时使用文本和图像。考虑到他们同时使用文本和图像参数,他们可能想同时使用。这是因为在示例3中,他对
image=image
部分进行了注释…至少我这样解释…Thx。我意识到我的问题不清楚“文本”。我不需要/不想显示文本。我应该在前两个代码段中从按钮中删除该选项。无论如何,感谢您的回答,解释了一切