Python - Congelación del botón Tkinter

CorePress2024-01-24  11

Digamos que tiene este programa:

import os
from tkinter import *
from time import sleep

def wait():
    print('waiting 5 seconds...')
    sleep(5)

def close():
    root.destroy()


root = Tk()
b = Button(text='click', command=wait)
close = Button(text='close', command=close)
b.pack()
close.pack()
mainloop()

Después de hacer clic en el botón "hacer clic", el botón se congela durante 5 segundos y luego vuelve a la normalidad. ¿Cómo hago para que no se congele? (No quiero eliminar la animación del botón, solo quiero que haga la animación del botón y luego espere 5 segundos). Además, cuando hago clic en "hacer clic", no puedo hacer clic en "cerrar". ¿Cómo soluciono esto?

sleep hace exactamente lo que anuncia: pone toda la aplicación en modo de suspensión.

-Bryan Oakley

27/03/2021 a las 22:07



------------------------------------

time.sleep() pausa toda la aplicación (incluida la ventana de tkinter), lo que significa que se congelará. Sin embargo, puedes utilizar la función root.after(). Un ejemplo práctico:

import tkinter

class MyApp:
    def __init__(self, parent):
        self.root = parent
        self.root.geometry("400x400")
        self.frame = tkinter.Frame(parent)
        self.frame.pack()
        self.root.after(3000, self.delayed)

    def delayed(self):
        print('I was delayed')

if __name__ == "__main__":
    root = tkinter.Tk()
    app = MyApp(root)
    root.mainloop()

El uso de root.after no congelará su aplicación durante el tiempo de espera. Nota: Debes especificar el tiempo de espera en milisegundos (1 segundo = 1000 milisegundos)

¡Espero poder ayudarte!



------------------------------------

Dado que time.sleep() es una función de bloqueo, no hay code se ejecutará hasta que se complete la llamada a la función. Para evitar que esto suceda, puede utilizar subprocesos para crear un subproceso que espere cinco segundos, pero permita que se ejecute otro código. Esto se llama multiprocesamiento, sobre el cual puedes leer más sobre multiprocesamiento aquí.

import threading
import time
import tkinter
import os

def wait():
    print('waiting 5 seconds...')
    threading.Thread(target=time.sleep, args=(5,)).start()

def close():
    root.destroy()


root = tkinter.Tk()
b = tkinter.Button(text='click', command=wait)
close = tkinter.Button(text='close', command=close)
b.pack()
close.pack()
root.mainloop()

2

Técnicamente, este ejemplo es correcto, pero con ese objetivo de subprocesamiento, saltaría inmediatamente a la siguiente línea y no esperaría. Lo necesitaría para saltar a otra función que tenga time.sleep y migrar el resto de la función aObjetivo de enhebrado.

- tayler6000

27/03/2021 a las 22:11

@tayler6000 Entonces creo que entendí mal la pregunta. Interpreté que deshabilité el botón durante 5 segundos, pero supongo que me equivoqué.

- Jacob Lee

27/03/2021 a las 22:15



------------------------------------

Tkinter puede resultar un poco confuso al principio. La mayoría de la gente piensa que Tkinter se ejecuta en un hilo separado de su código, pero en realidad no es así. Lo que significacuando usas time.sleep, tu programa se congela durante ese período de tiempo, lo que incluye Tkinter. Si el objetivo que intenta alcanzar es Wait5Seconds(); Hacer algo(); Recomendaría hacer lo siguiente:

import time

def wait():
    print('waiting 5 seconds...')
    stop = time.time() + 5
    while time.time() <= stop:
      time.sleep(.001)
    DoSomething()

Esta tampoco es la solución perfecta, ya que todavía implica dormir, pero es mejor. Puedes reemplazar eso con pass, pero la razón por la que tiendo a poner time.sleep en un bucle while diseñado específicamente para esperar es que si solo tienes un while x: pass, aumentará el núcleo de tu CPU, lo que puede causar un retraso significativo en un Computadora con bajo número de núcleos. La idea aquí es simplemente poner algo allí que tome algo de tiempo para que su CPU no se vuelva loca. Una posible alternativa que no he probado yo mismo pero que podría funcionar y no causaría ningún retraso en Tkinter es print('\r'), que simplemente establece elcursor de vuelta al principio de la línea. Lo que sobrescribirá lo que hay allí si aún no fuiste a una nueva línea, así que ten cuidado. Pero eso podría funcionar mejor ya que la salida a la pantalla en realidad requiere una cantidad decente de tiempo en términos de potencia de procesamiento, pero no bloqueará Tkinter. Para probar esto (suponiendo que esté en Windows), puede presionar LCtrl+LShift+Esc para abrir el Administrador de tareas, presionar más detalles (si es necesario) y luego ir a la pestaña Rendimiento. Asegúrese de que CPU esté seleccionada, luego haga clic derecho en el gráfico y seleccione Cambiar gráfico a > Procesadores lógicos, esto le mostrará la utilización de cada núcleo individualmente. De forma predeterminada, Python solo se ejecutará en un núcleo, aunque puede cambiar el núcleo que está usando al azar.

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare