Python代码问题,应用程序已被销毁Tcl错误
我正在制作一个Tkinter的图形界面,主要功能就是调用图片。不过,我一直在找合适的Tkinter文档,真是费了不少劲。
我有一行代码似乎无法按我想要的方式工作——我想把字典里的所有值都调出来,然后逐个打印,并根据每个值的名字拉取对应的图片,在调用下一个值之前完成这个过程。我试过使用dict.itervalues()和dict.values(),但就是搞不明白怎么做……
总之,这里是相关的代码片段:
for key in ansDict.iterkeys(): #using the iterkeys function... kind of
x=key
root = tk.Tk() # root window created (is this in the right place?)
root.title('C H E M I S T R Y A B C\'s')
frameAns=tk.Frame(root)
frameAns.grid(row=0, column=0, sticky=tk.NW)
for i in range(len(ansDict[x])):
print '-->' + ansDict[x][i]
for value in ansDict.itervalues(): #This is the most important part
for i in range(len(value)): #pulls value list from dictionary named ansDict
picRef1 = Image.open(value[i] + '.jpg') #calls image file by the same name using PIL
photo1 = ImageTk.PhotoImage(picRef1, master=root)
button1 = tk.Button(frameAns, compound=tk.TOP, image=photo1, text=str(value[i]) + '\nClose me!', bg='white') #pulls up button onto which the image is pasted
button1.grid(sticky=tk.NW, padx=2, pady=2) #places button on grid
button1.image=photo1
root.mainloop()
最后,代码执行到最后时,会拉出一两张图片,然后我就遇到了以下错误:
TclError: can't invoke "image" command: application has been destroyed
我搞不清楚问题出在哪里。我不能移动图片的命令,而且我需要以某种方式“保存”它,以免被销毁。我知道这里还有其他代码错误,但我觉得只要搞定这个TclError,其他问题也能解决。
如果有更简单的方法来实现这些功能,请告诉我!
3 个回答
这里有一个可能的方案,虽然它的结构和你的例子不太一样。这个方案是把四个100像素见方的图片一个叠一个地放在一起。我觉得你需要单独保存每个图片对象的引用,所以我把它们放在了一个叫做images的字典里。
from Tkinter import *
import os
from PIL import Image, ImageTk
image_names = { '1':'one','2':'two','3':'three','4':'four' }
images = {}
root = Tk()
root.title("HELLO")
frm = Frame(root)
for v in image_names.itervalues():
images[v] = {}
images[v]['i'] = Image.open("%s%s.jpg" % (os.path.dirname(__file__), v))
images[v]['pi'] = ImageTk.PhotoImage(images[v]['i'])
images[v]['b'] = Button(frm, image=images[v]['pi'])
images[v]['b'].pack()
frm.pack()
mainloop()
这里有一个不错的链接,讨论了PhotoImage类。
看起来你可能没有理解什么是事件驱动编程。你应该先创建好整个图形界面(GUI),然后把各种小部件放进去,设置好事件,最后进入一个无限循环。这个图形界面会根据你设置的事件来调用相应的回调函数。所以你程序中的某些部分确实只需要调用一次,比如:root = tk.Tk()
和root.mainloop()
。
编辑:添加了事件驱动编程的“想法示例”。
from Tkinter import *
master = Tk()
def callback():
print "click!"
b = Button(master, text="OK", command=callback)
b.pack()
mainloop()
我一直在寻找一个好的解决方案,但还没有找到合适的办法。查看Tkinter.py这个类,发现Image的del值是:
def __del__(self):
if self.name:
try:
self.tk.call('image', 'delete', self.name)
except TclError:
# May happen if the root was destroyed
pass
这意味着如果你想要做一个极端的黑客操作,你可以按照jtp的链接设置一个PhotoImage。
photo = tk.PhotoImage(file="C:/myimage.gif")
widget["image"] = photo
widget.image = photo
然后在程序退出之前,你可以做以下黑客操作:
photo.name = None
这样可以防止它在PhotoImage删除时尝试自我清理,从而避免在del方法中调用异常。我并不真的推荐你这样做,除非你真的没有其他选择,已经走投无路了。
我会继续研究这个问题,如果找到更好的解决方案,会更新这个帖子,希望在那之前有人能给出正确的解决办法。