Почему анимация надписи не работает до последнего значения цикла?

#python #animation #tkinter

#python #Анимация #tkinter

Вопрос:

Я новичок в python и недавно изучал tkinter. Итак, я подумал про себя, что с помощью функции grid_forget() я могу удалить виджет и переопределить его. Я подумал об этой анимации, которая изменяет заполнение надписи, чтобы она создавала пространство (вроде как перемещение надписи, но не совсем). Однако анимация вообще не работает. Программа зависает до тех пор, пока надпись не достигнет последнего значения заполнения. Как я могу это исправить? Или есть лучший способ анимировать перемещение надписи на экране? Вот мой код:

 from tkinter import *
import time

root = Tk()
lbl = Label(root, text='------')
lbl.grid(row=0, column=0)


def animation():
    padding = 0
    while padding < 31:
        lbl.grid_forget()
        padding  = 1
        lbl.grid(row=0, column=0, padx=padding)
        time.sleep(0.2)
        # alternative: root.after(200, lambda: lbl.grid(row=0, column=0, padx=padding))


btn = Button(root, text='Animate', command=animation)
btn.grid(row=1, column=1)
root.mainloop()
  

Комментарии:

1. Определенно есть лучший способ сделать анимацию. На этом сайте есть много примеров. Правильный способ анимации основан на вызове after .

Ответ №1:

Вам нужно обновить экран, чтобы отображались изменения.

Вот рабочая версия, использующая метод .update():

 from tkinter import *
import time

root = Tk()
lbl = Label(root, text='------')
lbl.grid(row=0, column=0)


def animation():
    padding = 0
    while padding < 31:
        lbl.grid_forget()
        padding  = 1
        lbl.grid(row=0, column=0, padx=padding)
        root.update()
        time.sleep(0.2)
        # alternative: root.after(200, lambda: lbl.grid(row=0, column=0, padx=padding))


btn = Button(root, text='Animate', command=animation)
btn.grid(row=1, column=1)
root.mainloop()
 
  

Комментарии:

1. Спасибо @Bruno Jambeiro! Это действительно сделало мой день! Только один вопрос. Почему мы должны использовать root.update()? Почему это не работает без этой функции?

2. Экран не обновляется автоматически, когда вы что-то меняете на нем, поэтому, когда вы меняете положение метки, изменения не будут показаны до следующего обновления экрана. В этой программе без функции root.update() перед обновлением применяется множество изменений, поэтому будет показано только последнее.

Ответ №2:

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

При этом используется широко используемый виджет Canvas из библиотеки tkinter.

Canvas — это виджет общего назначения, вы можете использовать его для многих вещей. Посетите гиперссылку для большей ясности

Вот краткий пример того, как вы могли бы создать текст на экране.

 from tkinter import *
root = Tk()

root.title("My animation")
c = Canvas(root)
x = 20 
y = 20    #Instead of using row and column, you simply use x and y co-ordinates
          #We will use these co-ordinates to show where the text is in the starting
my_text = c.create_text(x,y,text = '-----')
c.pack()

# This is all you need to create this text on your screen!
root.mainloop()
  

Идея в том, что вы размещаете свой холст в своем окне, а затем размещаете на нем все, что хотите.

Есть намного больше атрибутов, которые вы можете добавить, чтобы ваш текст выглядел еще лучше. Вот подробное руководство по этому.

Теперь, когда мы создали ваш текстовый виджет, пришло время его перемещать. Давайте переместим его на 90,20 из нашей начальной позиции, которая равна 20,20

Вот как мы это сделаем. Если мы просто перейдем к текстовому объекту на 90,90, мы не увидим никаких анимаций, они просто будут там напрямую. Итак, что мы сделаем, так это сначала создадим ее в 21,20. Затем 22,20. И так далее…

Мы делаем это очень быстро, пока не достигнем 90,20

Похоже, что мы перемещаем текст

 from tkinter import *
import time
root = Tk()

root.title("My animation")
c = Canvas(root)
x = 20
y = 20    #Instead of using row and column, you simply use x and y co-ordinates
          #We will use these co-ordinates to show where the text is in the starting
my_text = c.create_text(x,y,text = 'weee')
c.pack()

def animation():
    y = 0.1
    x = 0
    for _ in range(1000):
        c.move(my_text,x,y)
        root.update()


anlabel = Button(root,text = 'Animate!',command = animation).pack()

root.mainloop()


  

Это применимо не только к тексту, но и ко всему (например, к другим изображениям), что есть на холсте. У canvas также есть события, которые позволят вам использовать щелчки мыши и другие клавиши на компьютере.

Я внес некоторые изменения по сравнению с предыдущим кодом, но он исполняемый, и вы можете попробовать сами, чтобы увидеть, как это работает. увеличение значения в time.sleep() делает анимацию медленнее, чем меньше значение, тем быстрее.

Комментарии:

1. Почему вы вызываете c.pack() в цикле? Это абсолютно ничего не делает. Также нет причин удалять текстовый объект и затем создавать новый текстовый объект, когда вы можете просто переместить существующий объект.

2. Хорошо, спасибо за совет, я внесу следующие изменения

3. я внес изменения 🙂

4. Спасибо @AryanParekh ! Тем не менее, я хочу реализовать этот фрагмент кода в более крупной программе. Моя цель состоит в том, чтобы в моей основной программе я хотел, чтобы пользователь вводил строку в записи, и всякий раз, когда они нажимали «Кнопку отправки», этот текст перемещался по странице (что-то вроде имитации лазера), тогда текст внутри записи исчезал, потому что он был поражен этим текстом. Мой вопрос в том, будет ли этот метод работать в более крупной программе?

5. Да, безусловно!! Холсты потрясающие, вы можете узнать о них намного больше в этой серии YouTube, а также о самом Tkinter. youtube.com/playlist?list=PLCC34OHNcOtoC6GglhF3ncJ5rLwQrLGnV

Ответ №3:

Вы уверены, что не пытаетесь сделать что-то более похожее на приведенный ниже пример? Анимация заполнения на одном из ваших виджетов испортит остальную часть вашего дисплея.

 from tkinter import *
import time

root = Tk()
lbl = Label(root, text='')
lbl.grid(row=0, column=0)


def animation(step=12):
    step = 12 if step < 0 else step
    lbl['text'] = '      ------      '[step:step 6]
    root.after(200, lambda: animation(step-1))


Button(root, text='Animate', command=animation).grid(row=1, column=0, sticky='w')
root.mainloop()