Функция анимации изображения виджета Python tkinter с некорректным поведением после в цикле

Я медленно осваиваю Python и tkinter. :)

В игре, которую я создаю, есть анимация изображений, отображаемых внутри виджетов (а именно кнопок).

Покадровая анимация - это обычное дело, поэтому я придумал функцию, которая поможет мне автоматизировать 10-кадровую анимацию.

В цикле range(10) (так как у меня 10 кадров) функция вызывает метод after(), который имеет обратный вызов функции, каждый из которых отображает следующий кадр анимации.

Поскольку время в методе after увеличивается для каждой последующей итерации цикла, каждый новый кадр должен отображаться красиво по истечении заданного времени (здесь это 34 мс).

Теоретически это нормально, однако, когда я запускаю код и вызываю соответствующие функции, кнопка не анимируется должным образом. Кажется, выскакивает только последний кадр.

Я вижу это после некоторого чтения о том, как работает tkinter, так это то, что каждый after в цикле должен устанавливать независимый обратный вызов на «временной шкале» tkinter, который будет вызываться через некоторое время. Таким образом, на мой взгляд, этот код должен работать.

Что ты об этом думаешь? Что я не так, моя логика насчет after() в замкнутом цикле?

#Python 3.4.3
def animateMine(object):
    global firstAnimateMineCall
    for frame in range(10):
        frame += 1
        time = 34 * frame
        root.after(time, lambda: mineAnimationFrame(object, frame))
    if firstAnimateMineCall and frame == 10:
        root. after(500 , lambda: animateAllMines(object))
    firstAnimateMineCall = False

В сомнительном случае это пригодится:

def mineAnimationFrame(object, frame):
    tempDir = "Resources/Mine/saperx_mine_%s.png" % (frame)
    tempImage = PhotoImage(file=tempDir)
    object.configure(image=tempImage)
    object.image = tempImage
    object.disabled = True

person CyberGeneticist    schedule 02.08.2015    source источник
comment
На эту проблему давали ответ много раз. tempImage находится только в области видимости функции, поэтому при возврате функции mineAnimationFrame происходит сборка мусора, поэтому изображение для отображения не остается. См. Текст на зеленом фоне на странице effbot effbot.org/tkinterbook/photoimage.htm (и выполните поиск на этом сайте для чего-то вроде ссылки на изображение tkinter должно появиться много похожих сообщений)   -  person    schedule 03.08.2015
comment
@ curly-joe Вы явно не удосужились прочитать предоставленный мной код. Некоторое время назад я прочитал effbot, отличный сайт! Мой код подстраивается под это на object.image = tempImage, чтобы изображение не было мусором. Кроме того, если вы прочитали это, вы заметили, что я явно указал, что последний кадр виден, чего не было бы, если бы проблема была с возвратом мусора изображения func ... :)   -  person CyberGeneticist    schedule 03.08.2015
comment
@CurlyJoe Я снова отвечаю, потому что думаю, что ответ на сообщение не дошел до вас, и мне все еще нужна помощь с этой проблемой :)   -  person CyberGeneticist    schedule 03.08.2015
comment
Вы накладываете object.image каждый раз так, чтобы он содержал только последнее изображение = предыдущее изображение собиралось сборщиком мусора. Комментарий был намеком на то, что вы должны увидеть / распечатать, что содержит object.image после возврата из функции. Хорошее программирование IMHO было бы читать каждое изображение в list_of_images, а затем передавать число в функцию для отображения list_of_images [x]. И обратите внимание, что списки изменяемы, поэтому вам не нужно объявлять их глобальными. Ваш ответ был доставлен, но у меня есть время просматривать этот веб-сайт не чаще одного раза в день = от меня не будет никаких быстрых ответов.   -  person    schedule 04.08.2015
comment
Еще раз проверяем, решило ли это проблему или нет. Проверю еще раз завтра в личку   -  person    schedule 04.08.2015
comment
@CurlyJoe Спасибо за проверку: D Я уже некоторое время боролся с этим, и только сейчас понял, уфф. Вы помогли мне заметить, в чем я был неправ и в каком направлении двигаться, спасибо!   -  person CyberGeneticist    schedule 05.08.2015


Ответы (1)


Я придумал упрощенное, красивое и легко реализуемое решение этой проблемы (благодаря совету CurlyJoe).

* Основным преимуществом этого дизайна является то, что его легко настроить под количество кадров ... у вас есть 5? Просто измените 1 значение, и готово! Получил 900? Все еще легко. 6,02 * 10 ^ 23 кадров? По-прежнему всего 1 изменение;] *

Чтобы подстроиться под размер кадра, просто измените понимание списка range(10) на любое желаемое количество, все остальное позаботится код.

from tkinter import Tk, PhotoImage, Button, FLAT
root = Tk()
mineImagesList = [PhotoImage(file="Resources/Mine/saperx_mine_%s.png" % (frame)) for frame in range(1, 11)]
button = Button(root, bd=0, relief=FLAT, command= lambda: func(button))


def func (object, frame=0):
    object.configure(image=mineImagesList[frame])
    object.image = mineImagesList[frame]
    print("Object image:", object.image)
    if frame+1 < len(mineImagesList):
        frame += 1
        root.after(34, lambda frame=frame, object=object: func(object=object, frame=frame))

button.pack()
root.mainloop()
person CyberGeneticist    schedule 04.08.2015