I just dealt with this problem. I have an application that uses lots of "C" extensions that don't give the Python interpreter a chance to "time-slice" different threads. If I had simply had run the CPU intensive calculations in another thread, the user-interface thread would not get enough CPU to be responsive. The GUI thread sends requests to a 'dispatch' thread (using the 'Queue' mechanism). The 'dispatch' thread in turn sends requests to a "server" task using 'Pyro' (http://www.xs4all.nl/~irmen/python.html) Pyro lets you call methods in a remote Python task just as if the class was part of your task. It functions as a Python<->Python remote procedure call mechanism. Even though the computations are being done in a separate task, it is important to be able to see status messages from the server task. I captured the output of the remote task by spawning it using Process2.py, and then used 'input_add' to read the "server's" output. e.g.: from Process2 import Process proc = Process('dq_server', ('->', 1) ) proc.bg() self.__inputf = input_add( os.fdopen(proc.fd[1],'r'), GDK.INPUT_READ, self.__readServerOutput) def __readServerOutput(self, fp, condition): line = fp.readline() threads_enter() # subtle - to avoid deadlock, #threads_enter() can't proceed readline() # cleanup on EOF - avoid infinite stream of callbacks if line == "": input_remove(self.__inputf) fp.close() print 'Server closed\n' else: print ' -> %s' % line[0:-1] threads_leave() I also redirected standard output to appear in a widget, using code adapted from pygtk/examples/ide/gtkcons.py This allowed me to view both the server's output and the GUI's task output in a scrolling log window. I've attached my 'MessageWidget' that implements the scrolling log widget with output redirection. -- Joe VanAndel National Center for Atmospheric Research http://www.atd.ucar.edu/~vanandel/ Internet: [EMAIL PROTECTED]
""" MessageWidget: display a scrolled window of messages in a pygtk GtkText widget in a scrolled frame """ import sys from gnome.ui import * from gtk import * from gnome.config import * import libglade __id__ = "$Id: $" __version__ = "$Revision: $" # from pygtk/examples/ide/gtkcons.py class gtkoutfile: '''A fake output file object. It sends output to a gtk text widget, and if asked for a file number, returns one set on instance creation''' def __init__(self, w, fn, font): self.__fn = fn self.__w = w self.__font = font def close(self): pass flush = close def fileno(self): return self.__fn def isatty(self): return 0 def read(self, a): return '' def readline(self): return '' def readlines(self): return [] def write(self, s): #stdout.write(str(self.__w.get_point()) + '\n') self.__w.freeze() self.__w.insert(self.__font, self.__w.fg, self.__w.bg, s) # force a scroll to bottom vadj = self.__w.get_vadjustment() ## sys.stderr.write('lower: %d upper: %d value %d\n' % \ ## (vadj.lower, vadj.upper,vadj.value)) vadj.set_value(vadj.upper) self.__w.thaw() self.__w.queue_draw() def writelines(self, l): self.__w.freeze() for s in l: self.__w.insert(self.__font, self.__w.fg, self.__w.bg, s) vadj = self.__w.get_vadjustment() vadj.set_value(vadj.upper) self.__w.thaw() self.__w.queue_draw() def seek(self, a): raise IOError, (29, 'Illegal seek') def tell(self): raise IOError, (29, 'Illegal seek') truncate = tell class MessageWidget: def __init__(self, text_w, wordWrap =TRUE): self.debug = FALSE print 'MessageWidget:__init__' self.text = text_w self.text.style = self.text.get_style() self.text.fg = self.text.style.fg[STATE_NORMAL] self.text.bg = self.text.style.white #self.text.bg = self.text.style.bg[STATE_NORMAL] self.text.set_word_wrap(wordWrap) self.text.set_usize(500, 400) self.normal = load_font( "-*-helvetica-medium-r-normal-*-*-100-*-*-*-*-*-*") self.error = load_font( "-*-helvetica-medium-o-normal-*-12-100-*-*-*-*-*-*") # set up hooks for standard output. self.stdout = gtkoutfile(self.text, sys.stdout.fileno(), self.normal) self.stderr = gtkoutfile(self.text, sys.stderr.fileno(), self.error) def init(self, debug=0): self.debug = debug self.text.realize() # print 'MessageWidget:text realized ' if not self.debug: sys.stdout, self.stdout = self.stdout, sys.stdout #sys.stderr, self.stderr = self.stderr, sys.stderr else: print 'debug mode : not grabbing standard output' def restore(self): if not self.debug: sys.stdout, self.stdout = self.stdout, sys.stdout # sys.stderr, self.stderr = self.stderr, sys.stderr return