Por que a animação fade in não está funcionando, mas a animação fade out funciona?
Eu sou novo em python e tive a ideia de como fazer uma animação de fade simples em python usando tkinter e o módulo de tempo . Eu defini duas animações para o programa: uma para fade in e outra para fade out. A animação fade out funciona perfeitamente e exatamente como eu quero que seja, no entanto, a animação fade in não funciona de todo. O programa praticamente não aparece até que o loop while termine. Estou fazendo algo errado ou é simplesmente impossível criar um fade em vigor no python tkinter? Aqui está meu snippet de código:
from tkinter import *
import time
root = Tk()
transparency = 0
while transparency <= 1:
transparency += 0.1
root.wm_attributes("-alpha", transparency)
time.sleep(0.03)
def fade():
t = 1
while t > 0:
t -= 0.1
root.wm_attributes("-alpha", t)
time.sleep(0.03)
root.destroy()
btn = Button(root, text='fade exit', command=fade).pack()
root.mainloop()
Respostas
Em vez de usar while
loops e time
, use after(millis, function)
e recursão.
bônus:
- use os argumentos da função para personalizar o efeito e comportamento de esmaecimento
- isso não impedirá a atualização do root
- tudo está encapsulado
- essas funções podem ser usadas em qualquer
Toplevel
janela applyFades
gerencia tudo em uma chamada
Se você absolutamente necessário anexar esses recursos para um Button
, simplesmente atribuir o command
argumento como este: command=lambda: fadeOut(root)
.
window.py
''' Fade In
@window ~ the window to affect
@millis ~ the amount of milliseconds to wait before next recursion
@inc ~ the amount to increment alpha on each recursion
'''
def fadeIn(window, millis:int=50, inc:float=0.1):
alpha = float(window.attributes('-alpha')) + inc
window.attributes('-alpha', alpha)
if alpha < 1:
window.after(millis, lambda: fadeIn(window, millis, inc))
else:
window.attributes('-alpha', 1.0)
''' Fade Out
@window, @millis ~ see: Fade In
@dec ~ the amount to decrement alpha on each recursion
@destroy ~ True|False destroy the window when effect is complete
'''
def fadeOut(window, millis:int=50, dec:float=0.1, destroy:bool=True):
alpha = float(window.attributes('-alpha')) - dec
window.attributes('-alpha', alpha)
if alpha > 0:
window.after(millis, lambda: fadeOut(window, millis, dec, destroy))
else:
window.attributes('-alpha', 0.0)
if destroy:
window.destroy()
''' Assign All Fades In One Call
@window, @millis, @inc ~ see: Fade In
@dec, @destroy ~ see: Fade Out
@close ~ True|False add fadeOut effect to window close button
'''
def applyFades(window, millis:int=50, inc:float=0.1, dec:float=0.1, destroy:bool=True, close:bool=True):
window.attributes('-alpha', 0.0)
window.after(millis, lambda: fadeIn(window, millis, inc))
if close:
window.protocol("WM_DELETE_WINDOW", lambda: fadeOut(window, millis, dec, destroy))
main.py
import tkinter as tk
import window as win
root = tk.Tk()
win.applyFades(root)
root.mainloop()
Vamos ver o que seu script faz. No início root = Tk()é atribuído o que inicia um interpretador tcl / tk e cria uma janela raiz. Em seguida, ele controla seu atributo de opacidade para fade in. Depois disso, um widget de botão é colocado na janela raiz que tem estas propriedades:
- um texto 'fade exit' é escrito na parte superior do widget
- ele espera por um clique do mouse e depois controla o atributo de opacidade de uma janela raiz para desaparecer.
Finalmente, root.mainloop()é um substituto para
while True:
root.update_idletasks()
root.update()
Você deve prestar atenção que o botão 'fade in' está sendo criado no momento em que sua janela raiz não é atualizada. Esse é o motivo pelo qual você não consegue ver o fade in real.
Solução 1. Atualizando a janela raiz após cada amostra de fading in:
from tkinter import *
import time
def fade():
t = 1
while t > 0:
t -= 0.1
root.wm_attributes("-alpha", t)
time.sleep(0.03)
root.destroy()
root = Tk()
transparency = 0
btn = Button(root, text='fade in', command=fade)
btn.pack()
while transparency <= 1:
transparency += 0.1
root.wm_attributes("-alpha", transparency)
root.update_idletasks()
root.update()
time.sleep(0.03)
btn.configure(text='fade exit') #I guess no new button is needed and text should be replaced only
root.mainloop()
Solução 2. É mais comum não usar tkinter
em combinação com um método de time
uso after
. Verifique a resposta de Michael.