¿Por qué no funciona el desvanecimiento en la animación pero sí funciona la animación de desvanecimiento?

Aug 18 2020

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

2 MichaelGuidry Aug 18 2020 at 03:28

En lugar de usar whilebucles 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 Toplevelventana
  • applyFades gestiona todo en una llamada

Si es absolutamente necesario que conecte estas características a una Button, sólo tiene que asignar el commandargumento 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()
2 mathfux Aug 18 2020 at 03:34

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 tkinteren combinación con un método de timeuso after. Mira la respuesta de Michael.