python - example - Uso del módulo de multiprocesamiento para actualizar la GUI de Tkinter
tkinter python buttons (2)
He intentado usar el módulo de multiprocesamiento para actualizar la GUI de Tkinter, pero cuando ejecuto este código, me da un error de decapado.
# Test Code for Tkinter with threads
import Tkinter
from multiprocessing import Queue
import multiprocessing
import time
# Data Generator which will generate Data
def GenerateData():
global q
for i in range(10):
print "Generating Some Data, Iteration %s" %(i)
time.sleep(2)
q.put("Some Data from iteration %s /n" %(i))
def QueueHandler():
global q, text_wid
while True:
if not q.empty():
str = q.get()
text_wid.insert("end", str)
# Main Tkinter Application
def GUI():
global text_wid
tk = Tkinter.Tk()
text_wid = Tkinter.Text(tk)
text_wid.pack()
tk.mainloop()
if __name__ == ''__main__'':
# Queue which will be used for storing Data
tk = Tkinter.Tk()
text_wid = Tkinter.Text(tk)
q = multiprocessing .Queue()
t1 = multiprocessing.Process(target=GenerateData,args=(q,))
t2 = multiprocessing.Process(target=QueueHandler,args=(q,text_wid))
t1.start()
t2.start()
text_wid.pack()
tk.mainloop()
Error:
PicklingError: Can''t pickle <type ''thread.lock''>: it''s not found as thread.lock
Si text_wid
el argumento text_wid
, no se informa ningún error, pero el widget de texto no se actualiza con los datos del queque.
ACTUALIZAR:
Modifiqué el código para llamar a la función para actualizar la GUI siempre que haya valor en la cola, evitando así que los widgets Tkinter se pasen a un proceso separado. Ahora, no recibo ningún error, pero el widget no se actualiza con los datos. Sin embargo, si uso la mezcla del módulo de Threading
y Multiprocessing
, es decir, creo una secuencia separada para manejar los datos de la cola, entonces funciona bien. Mi pregunta por qué no funcionó cuando ejecuto el código del controlador en un proceso separado. ¿No estoy pasando los datos correctamente? A continuación está el código modificado:
# Test Code for Tkinter with threads
import Tkinter
import multiprocessing
from multiprocessing import Queue
import time
import threading
# Data Generator which will generate Data
def GenerateData(q):
for i in range(10):
print "Generating Some Data, Iteration %s" %(i)
time.sleep(2)
q.put("Some Data from iteration %s /n" %(i))
def QueueHandler(q):
while True:
if not q.empty():
str = q.get()
update_gui(str)
#text_wid.insert("end", str)
# Main Tkinter Application
def GUI():
global text_wid
tk = Tkinter.Tk()
text_wid = Tkinter.Text(tk)
text_wid.pack()
tk.mainloop()
def update_gui(str):
global text_wid
text_wid.insert("end", str)
if __name__ == ''__main__'':
# Queue which will be used for storing Data
tk = Tkinter.Tk()
text_wid = Tkinter.Text(tk)
q = multiprocessing.Queue()
t1 = multiprocessing.Process(target=GenerateData,args=(q,))
t2 = multiprocessing.Process(target=QueueHandler,args=(q,))
t1.start()
t2.start()
text_wid.pack()
tk.mainloop()
Te perdiste una parte importante, debes proteger tus llamadas con una trampa __main__
:
if __name__ == ''__main__'':
q = Queue.Queue()
# Create a thread and run GUI & QueueHadnler in it
t1 = multiprocessing.Process(target=GenerateData,args=(q,))
t2 = multiprocessing.Process(target=QueueHandler,args=(q,))
....
Tenga en cuenta que la cola se pasa como un parámetro en lugar de utilizar un global.
Editar: acaba de detectar otro problema, debe usar Queue
del módulo de multiprocessing
, no de la Queue
:
from multiprocessing import Queue
# Test Code for Tkinter with threads
import Tkinter as Tk
import multiprocessing
from Queue import Empty, Full
import time
class GuiApp(object):
def __init__(self,q):
self.root = Tk.Tk()
self.root.geometry(''300x100'')
self.text_wid = Tk.Text(self.root,height=100,width=100)
self.text_wid.pack(expand=1,fill=Tk.BOTH)
self.root.after(100,self.CheckQueuePoll,q)
def CheckQueuePoll(self,c_queue):
try:
str = c_queue.get(0)
self.text_wid.insert(''end'',str)
except Empty:
pass
finally:
self.root.after(100, self.CheckQueuePoll, c_queue)
# Data Generator which will generate Data
def GenerateData(q):
for i in range(10):
print "Generating Some Data, Iteration %s" %(i)
time.sleep(2)
q.put("Some Data from iteration %s /n" %(i))
if __name__ == ''__main__'':
# Queue which will be used for storing Data
q = multiprocessing.Queue()
q.cancel_join_thread() # or else thread that puts data will not term
gui = GuiApp(q)
t1 = multiprocessing.Process(target=GenerateData,args=(q,))
t1.start()
gui.root.mainloop()
t1.join()
t2.join()