pygtk threads subprocess
6 Nov 2009 | Escrito por: lopz | En: Python
pygtk threads subprocess commands
Hola
Después de mucho tiempo sin escribir nada paso a poner una breve nota sobre el uso de threads en pygtk, en google hay mucha información al respecto, inclusive en su página hay esto:
http://faq.pygtk.org/index.py?file=faq20.006.htp&req=show
Y bueno, escribí un pequeño trozo de código que será fácil entender si se lee el anterior link, en esta ocasión pasaré de escribir línea a línea el script xD
Code:import gtk
import os
import subprocess as sp
import time
import threading
gtk.gdk.threads_init()
#gobject.threads_init()
CMD = 'du -sh /home/lopz/'
class MainWin:
"""
Creates a main window object
"""
def __init__(self):
w = gtk.Window()
self.pb = gtk.ProgressBar()
box = gtk.HBox(False, 0)
self.btn_start = gtk.Button("Start")
self.btn_start.connect("clicked", self.btn_start_click)
box.pack_start(self.btn_start)
btn_test = gtk.Button("Test")
btn_test.connect("clicked", self.btn_test_click)
box.pack_end(btn_test)
self.btn_stop = gtk.Button("Stop")
self.btn_stop.connect("clicked", self.btn_stop_click)
self.btn_stop.set_sensitive(False)
box.pack_end(self.btn_stop)
box.pack_start(self.pb)
w.add(box)
w.show_all()
w.connect("destroy", self.quit)
def get_popen(self, cmd):
return sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.STDOUT)
def pulse(self):
while not self.quit:
time.sleep(0.1)
gtk.gdk.threads_enter()
self.pb.pulse()
gtk.gdk.threads_leave()
def exec_cmd(self):
self.popen = self.get_popen(CMD.split())
out = self.popen.stdout.read()
if out:
print out
self.terminate()
def terminate(self):
self.quit = True
os.kill(self.popen.pid, 9)
self.btn_stop.set_sensitive(False)
self.btn_start.set_sensitive(True)
print "Terminate threads"
def quit(self, widget):
gtk.main_quit()
self.terminate()
def btn_test_click(self, widget):
print "gtkMain thread"
def btn_stop_click(self, widget):
self.pb.set_text("Completed")
self.terminate()
def new_thread(self, method):
t = threading.Thread(target=method, args=())
t.start()
def btn_start_click(self, widget):
print "Start threads"
self.quit = False
self.btn_stop.set_sensitive(True)
widget.set_sensitive(False)
self.pb.set_text('Running')
self.new_thread(self.pulse)
self.new_thread(self.exec_cmd)
if __name__ == "__main__":
gui = MainWin()
gtk.gdk.threads_enter()
gtk.main()
gtk.gdk.threads_leave()
A grandes rasgos lo que hace el script es lo siguiente:
crea una ventana con unos 3 widgets dentro, un progressbar y 3 botones, el progressbar es para mostrar al usuario que aún se está realizando la tarea, el botón start pues empieza la tarea, el stop detiene todo y el test lo que hace simplemente es imprimir en consola.
Start: Lanzará 2 threads, en uno lo que hacemos es modificar los widgets, ahí puedes modificar cualquier parte de la interfaz mientras estás haciendo alguna tarea junto a este threads lanza otro donde se ejecutará nuestra tarea pesada, en este caso el comando du -sh /home/tu_user que lo que hace es mostrar el tamaño del directorio, como este comando tiende a tardar en mostrar el resultado al usuario le mostraremos una barra de progreso para que sea que aún se está realizando la tarea.
stop: lo que hace es terminar ambos hilos, el que muestra la barra de progreso y el que ejecuta el comando, en este caso matando el pid del comando y automáticamente sale del hilo.
test: este botón es una prueba que podemos usar nustra gui mientras ejecutamos tareas pesadas por debajo, y este solo imprime en consola desde el thread de main.
El botón salir de la ventana hace lo mismo que el botón Stop, para ambos threads y luego destruye la ventana del hilo principal, si no destruimos los hilos uno quedará pegado hasta que termine de ejecutarse nuestro comando, cosa que no queremos.
Creo que es todo, para ser un pequeño ejemplo para ayudar a un amigo va bien y de paso recordé un poco esto de python que lo tengo ya olvidado.
A continuación pasaré como siempre a pegar una pequeña captura de pantalla de la pequeña gui funcionando.

Espero que a alguien le sirva y deja algún comentario.
Igual se puede usar gobject.idle_add(mi_funcion) pero esto no toqué para nada.
tampoco he visto cual sea la manera correcta o la mejor de hacerlo.
Tu amigo programador de python+pygtk ¿Cómo solucionas este tipo de problemas?
Saludos!
|