Multihilo en Tkinter GUI, hilos en diferentes clases

Actualmente estoy aprendiendo la progtwigción GUI Tkinter. Y estoy atrapado en algún lugar en el concepto de subprocesos múltiples. Aunque este tema se discute varias veces aquí, no pude captar el concepto y aplicarlo a mi pequeño progtwig de muestra.

A continuación se muestra mi código:

from PIL import Image, ImageTk from Tkinter import Tk, Label, BOTH from ttk import Frame, Style from Tkinter import * import time class Widgets(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.grid() self.parent = parent self.initUI(parent) def initUI(self, parent): self.parent.title("Count Numbers") for r in range(10): self.parent.rowconfigure(r, weight=1) for c in range(10): self.parent.columnconfigure(c, weight=1) self.button1 = Button(parent, text = "count") self.button1.grid(row = 1, column = 1, rowspan = 1, columnspan = 2, sticky = W+E+N+S ) self.button1["command"] = self.countNum self.button2 = Button(parent, text = "say Hello") self.button2.grid(row = 1, column = 7, rowspan = 1, columnspan = 2, sticky = W+E+N+S) self.button2["command"] = PrintHello(self).helloPrint def countNum(self): for i in range(10): print i time.sleep(2) class PrintHello(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.grid() self.parent = parent def helloPrint(self): print "Hello" def main(): root = Tk() root.geometry("300x200") app = Widgets(root) root.mainloop() if __name__ == '__main__': main() 

introduzca la descripción de la imagen aquí

La salida es una GUI con 2 botones: el primero imprime los números y el segundo imprime “Hola”. Pero al hacer clic en el primer botón, la GUI se congela mientras se imprimen los números. Y mientras buscaba una solución, encontré que el ‘subprocesos múltiples’ podría ayudar. Pero después de varios bashs, no pude aplicar subprocesos múltiples a mi progtwig de muestra dado.

No necesitas enhebrar para algo tan simple.

La interfaz gráfica de usuario se está congelando porque está poniendo un time.sleep dentro de la función que bloquea el hilo principal hasta que finaliza.

Simplemente use el método incorporado de Tk. Cambia tu función a.

 def countNum(self, num=0): if num < 10: print num root.after(2000, lambda: self.countNum(num + 1)) else: print "Stopping after call" 

El método after toma los siguientes argumentos:

 after(delay_ms, callback, arguments) 

El tiempo es en milisegundos y 1000 ms = 1 segundo. Entonces, pasamos 2,000 ms para un retraso de 2 segundos.

La respuesta del pitonista es excelente. Pero me gustaría tocar algunos puntos adicionales.

  • GUI son impulsados ​​por eventos . Se ejecutan en un bucle procesando eventos, llamando partes de su código (llamadas devoluciones de llamada) de vez en cuando. Así que su código es más o menos un invitado en el bucle de eventos. Como ha notado, sus piezas de código deben terminar rápidamente, de lo contrario, se detendrá el procesamiento del evento, lo que hará que la GUI no responda. Este es un modelo de progtwigción completamente diferente de los progtwigs lineales que se ve a menudo en los tutoriales. Para realizar cálculos o tareas de ejecución más larga, puede dividirlos en partes pequeñas y usar after . O podrías en otro proceso con multiprocessing . Pero entonces aún tendrías que revisar periódicamente (con after otra vez) si han terminado.

Los siguientes puntos se derivan del hecho de que hacer el derecho de subprocesos múltiples es difícil .

  • CPython (la implementación de Python más utilizada) tiene lo que se denomina locking global de intérprete. Esto garantiza que solo un hilo a la vez pueda ejecutar el bytecode de Python. Cuando otros subprocesos están ocupados ejecutando el código de bytes de Python, el subproceso que ejecuta la GUI no hace nada. Por lo tanto, el subprocesamiento múltiple no es una solución segura al problema de una GUI que no responde.

  • muchos de los kits de herramientas GUI no son seguros para subprocesos, y tkinter no es una excepción. Esto significa que solo debes hacer llamadas tkinter desde el hilo que ejecuta mainloop .