Проблема с кодом 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: невозможно вызвать команду "изображение": приложение было уничтожено
и я не могу понять, что не так. Я не могу переместить команду изображения, и каким-то образом мне нужно "сохранить" ее, чтобы она не была уничтожена. Я знаю, что здесь есть и другие ошибки в коде, но я думаю, что, если я выясню, что получаю TclError, я могу исправить все остальное.
Если есть более простой способ сделать это, пожалуйста, сообщите!
3 ответа
Я искал хорошее решение для этого, но пока не нашел правильного решения. Глядя на класс 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
Это означает, что если вы хотите сделать ЗЛОКАЧЕЕ взлом, вы можете установить PhotoImage, как описано в ссылке jtp.
photo = tk.PhotoImage(file="C:/myimage.gif")
widget["image"] = photo
widget.image = photo
Тогда вы могли бы незадолго до выхода из программы сделать следующий хак:
photo.name = None
Это не позволит ему попытаться очистить себя при удалении PhotoImage и не вызовет исключение в методе del. Я действительно не рекомендую вам делать это, если вы не прислонились спиной к стене, и у вас нет альтернативы.
Я буду продолжать изучать это, и если я найду лучшее решение, отредактирую этот пост с лучшим (надеюсь, кто-то даст правильное решение до этого).
Похоже, вы не поняли, что такое программирование на основе событий. Вы должны создать целый графический интерфейс один раз, заполнить его виджетами, настроить события и затем войти в бесконечный цикл. 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()
Вот одна из возможностей, хотя она структурирована иначе, чем ваш пример. Он накладывает четыре квадрата размером 100 пикселей друг на друга. Я считаю, что вам нужно хранить отдельную ссылку на каждый объект Image, поэтому я спрятал их в словаре изображений.
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.