python - 无法在 windows 上将图像添加到 GUI(tkinter)

python - unable to add image to the GUI(tkinter) on windows

我正在使用 python(我的版本是 2.7)。我想将图像添加到 GUI (Tkinter),然后使用 pyinstaller 转换为可执行格式。 我确实按照SO, and also as said on ActiveState

当我在代码中提到图像的路径时,只有当我直接 运行 时它才有效。如果我将它转换为 exe 它不会打开。

更改其他解决方案中提到的代码,例如将其转换为编码字符串,运行在 linux 上没问题。但是在 windows 上它会抛出错误

代码:

from Tkinter import *
from PIL import ImageTk, Image

logo = '''
----- encoded string -----
'''

root = Tk()
logoimage = Tkinter.PhotoImage(master=root, data=logo)
Label(root, image=logoimage).pack()
root.mainloop()

变化一: 上面的代码适用于 linux。在 windows 上,我在行 logoimage = Tkinter.PhotoImage(master=root, data=logo) 上收到错误,因为

NameError: name 'Tkinter' is not defined

变化2: 所以我尝试将行更改为 logoimage = ImageTk.PhotoImage(master=root, data=logo)。我得到的错误是

File "C:\Python27\lib\site-packages\PIL\ImageTk.py", line 88, in __init__
    image = Image.open(BytesIO(kw["data"]))
  File "C:\Python27\lib\site-packages\PIL\Image.py", line 2330, in open
    % (filename if filename else fp))
IOError: cannot identify image file <_io.BytesIO object at 0x00000000024BB150>
Exception AttributeError: "'PhotoImage' object has no attribute '_PhotoImage__photo'" in <bound method PhotoImage.__del__ of <PIL.ImageTk.PhotoImage object at 0x00000000024D49E8>> ignored

变化3: 但是,如果我将行更改为 iconImage= ImageTk.PhotoImage(Image.open('path_to_image.png'))。只有当我直接 运行 时它才有效。如果我将其转换为可执行文件,则控制台会打开 2-3 秒并显示类似 Unable to locate the image file

的错误
from Tkinter import *
#...
logoimage = Tkinter.PhotoImage(master=root, data=logo)

如果您使用 import * 将 Tkinter 模块直接转储到全局范围内,那么您不应该在 class 和函数名称前加上模块名称。删除前缀,或删除 import *.

import Tkinter
#...
logoimage = Tkinter.PhotoImage(master=root, data=logo)

或者

from Tkinter import *
#...
logoimage = PhotoImage(master=root, data=logo)

我怀疑您没有收到 Linux 中的错误,因为您的 Python 版本会自动导入通用模块。实际上,所有脚本的顶部都有一个不可见的 import Tkinter

明确地进行解码和转换可能比您目前所做的更可靠。此代码适用于 Python 2.6.6 Linux。

import io, base64
from Tkinter import *
from PIL import ImageTk, Image

#A simple 64x64 PNG fading from orange in the top left corner 
# to red in the bottom right, encoded in base64
logo_b64 = '''
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIA
AAAlC+aJAAAA/0lEQVR4nO3Zyw7CMAxEUdP//+W2rCqBoJA2noclS1kn9yjLeex7xKY76+
wNS+l6KSCjXgdIqhcB8uoVgNR6OiC7ngsA1BMBmHoWAFZPASDr8QBwPRiAr0cCKPUwAKse
AyDWAwDc+mwAvT4VoKjPA4jqkwC6+gyAtD7WSYC6fu4HDOonAB71dwE29bcATvXXAWb1Fw
F+9VcAlvXDANf6MYBx/QDAu/4fwL7+J6BC/TmgSP0JoE79N0Cp+g9Atfp3QMH6F0DN+gNQ
tj62WErXB2PgQNZLAb3U6wC91OsAvdTrAL3U6wC91OsAvdTrAL3U6wC91OsAvdTrAL3Uz7
z+BNmX4gqbppsaAAAAAElFTkSuQmCC
'''

#Decode the PNG data & "wrap" it into a file-like object
fh = io.BytesIO(base64.b64decode(logo_b64))

#Create a PIL image from the PNG data
img = Image.open(fh, mode='r')

#We must open the window before calling ImageTk.PhotoImage
root = Tk()

photo = ImageTk.PhotoImage(image=img)
Label(root, image=photo).pack()
Label(root, text='An embedded\nbase64-encoded PNG').pack()
root.mainloop()

作为参考,这是嵌入的 PNG 的样子。