¿Por qué no funciona el desvanecimiento en la animación pero sí funciona la animación de desvanecimiento?
Soy nuevo en Python y se me ocurrió esta idea sobre cómo hacer una animación de desvanecimiento simple en Python usando tkinter y el módulo de tiempo . He definido dos animaciones para el programa: una para aparecer y otra para desaparecer. La animación de fundido funciona perfectamente y exactamente como quiero que sea, sin embargo, la animación de fundido no funciona en absoluto. El programa prácticamente no aparece hasta que finaliza el ciclo while. ¿Estoy haciendo algo mal o es simplemente imposible crear un efecto de desvanecimiento en python tkinter? Aquí está mi fragmento 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()
Respuestas
En lugar de usar while
bucles y time
, use after(millis, function)
y recursividad.
bonificaciones:
- use los argumentos de la función para personalizar el efecto y el comportamiento de desvanecimiento
- esto no impedirá que la raíz se actualice
- todo esta encapsulado
- estas funciones se pueden utilizar en cualquier
Toplevel
ventana applyFades
gestiona todo en una llamada
Si es absolutamente necesario que conecte estas características a una Button
, sólo tiene que asignar el command
argumento de la siguiente manera: 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()
Veamos qué hace tu script. Al principio root = Tk()se asigna lo que inicia un intérprete tcl / tk y crea una ventana raíz. Luego controla su atributo de opacidad para que se desvanezca. Después de eso, se coloca un widget de botón en la ventana raíz que tiene estas propiedades:
- se escribe un texto 'fade exit' en la parte superior del widget
- espera un clic del mouse y luego controla el atributo de opacidad de una ventana raíz para que desaparezca.
Finalmente, root.mainloop()es un sustituto de
while True:
root.update_idletasks()
root.update()
Es posible que preste atención a que el botón 'fade in' se está creando en el momento en que su ventana raíz no está actualizada. Esta es una razón por la que no puede ver el desvanecimiento real.
Solución 1. Actualización de la ventana raíz después de cada muestra de aparición gradual:
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()
Solución 2. Es más típico no usar tkinter
en combinación con un método de time
uso after
. Mira la respuesta de Michael.