Mengapa animasi fade in tidak berfungsi, tetapi animasi fade out berfungsi?

Aug 18 2020

Saya baru mengenal python dan saya mendapatkan ide tentang cara membuat animasi pudar sederhana di python menggunakan tkinter dan modul waktu . Saya telah menetapkan dua animasi untuk program: satu untuk memudar dan yang lainnya memudar. Animasi fade out bekerja dengan sempurna dan persis seperti yang saya inginkan, namun animasi fade out tidak berfungsi sama sekali. Program ini tidak akan muncul sampai while loop selesai. Apakah saya melakukan sesuatu yang salah atau tidak mungkin membuat efek fade di python tkinter? Ini cuplikan kode saya:

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()

Jawaban

2 MichaelGuidry Aug 18 2020 at 03:28

Alih-alih menggunakan whileloop dan time, gunakan after(millis, function)dan rekursi.

bonus:

  • gunakan argumen fungsi untuk menyesuaikan efek fade dan perilaku
  • ini tidak akan memblokir root dari pembaruan
  • semuanya dikemas
  • fungsi ini dapat digunakan di Topleveljendela mana pun
  • applyFades mengelola semuanya dalam satu panggilan

Jika Anda benar-benar perlu melampirkan fitur ini ke Button, hanya menetapkan commandargumen seperti ini: 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

Mari kita lihat apa yang skrip Anda lakukan. Pada awalnya root = Tk()ditugaskan yang memulai interpreter tcl / tk dan membuat jendela root. Kemudian ia mengontrol atribut opacity untuk fade in. Setelah itu widget Button ditempatkan pada jendela root yang memiliki properti berikut:

  • teks 'fade exit' tertulis di bagian atas widget
  • itu menunggu klik mouse dan setelah itu mengontrol atribut opacity dari jendela root untuk memudar.

Akhirnya, root.mainloop()adalah pengganti

while True:
    root.update_idletasks()
    root.update()

Anda mungkin memperhatikan bahwa tombol 'fade in' sedang dibuat saat jendela root Anda tidak diperbarui. Inilah alasan mengapa Anda tidak dapat melihat fade in yang sebenarnya.

Solusi 1. Memperbarui jendela root setelah setiap sampel memudar:

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()

Solusi 2. Ini lebih umum untuk tidak digunakan tkinterdalam kombinasi dengan timedan menggunakan aftermetode. Lihat jawaban Michael.