Pourquoi l'animation en fondu ne fonctionne-t-elle pas alors que l'animation en fondu sortant fonctionne?
Je suis nouveau en python et j'ai eu cette idée sur la façon de créer une simple animation de fondu en python en utilisant tkinter et le module time . J'ai défini deux animations pour le programme: une pour fondre et l'autre pour disparaître. L'animation en fondu fonctionne parfaitement et exactement comme je le souhaite, cependant, l'animation en fondu ne fonctionne pas du tout. Le programme n'apparaît quasiment pas tant que la boucle while n'est pas terminée. Est-ce que je fais quelque chose de mal ou est-il tout simplement impossible de créer un effet de fondu en python tkinter? Voici mon extrait de code:
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()
Réponses
Au lieu d'utiliser des while
boucles et time
, utilisez after(millis, function)
et récursivité.
bonus:
- utiliser les arguments de la fonction pour personnaliser l'effet et le comportement du fondu
- cela n'empêchera pas la racine de se mettre à jour
- tout est encapsulé
- ces fonctions peuvent être utilisées sur n'importe quelle
Toplevel
fenêtre applyFades
gère tout en un seul appel
Si vous avez absolument besoin d'attacher ces caractéristiques à un Button
, il suffit d' attribuer l' command
argument de la manière suivante: 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()
Voyons ce que fait votre script. Au début root = Tk()est assigné qui démarre un interpréteur tcl / tk et crée une fenêtre racine. Ensuite, il contrôle son attribut d'opacité pour qu'il disparaisse. Après cela, un widget Button est placé sur la fenêtre racine qui a ces propriétés:
- un texte 'fade exit' est écrit en haut du widget
- il attend un clic de souris et après avoir contrôlé l'attribut d'opacité d'une fenêtre racine pour disparaître.
Enfin, root.mainloop()est un substitut à
while True:
root.update_idletasks()
root.update()
Vous pouvez faire attention au fait que le bouton «fondu entrant» est en cours de création au moment où votre fenêtre racine n'est pas mise à jour. C'est une raison pour laquelle vous ne pouvez pas voir le fondu réel.
Solution 1. Mise à jour de la fenêtre racine après chaque échantillon de fondu:
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()
Solution 2. Il est plus courant de ne pas utiliser tkinter
en combinaison avec une méthode d' time
utilisation after
. Regardez la réponse de Michael.