############################################################ # # ***PLEASE NOTE: THIS IS NEITHER COMPLETE NOR CORRECT*** # # adds support for shell cmd runs, nonblocking func calls, # stay-up output displays; to do: make input come from a # stay-up entry field, not a popup per line; # warning: redirect func resets stdin/out for entire # process--may lead to odd behaviour (if not blocking); # also possible: Tk file event handler, but # doesn't yet work on MS-Windows under Tk 8.0; # gui shell cmd could also reset sys.stdout and use print, # but that resets stdout for entire process; # if no gui AppActive: mainloop() (now assumes is); # could 'return output' too, but just assume that caller # will create a box and pass in, if it is to be processed # after the redirect utility call; ############################################################ from Tkinter import * from guiStreams import GuiInput, GuiOutput import os, sys, thread # # client tools # BLOCK, THREAD, ONIDLE = 'block', 'thread', 'onidle' def redirectGuiFunc(func, pargs, kargs, mode=BLOCK, currBox=None): streams = sys.stdin, sys.stdout sys.stdin = GuiInput() # run func with its sys.stdout = currBox or GuiOutput(Toplevel()) # stdin/out streams if mode == BLOCK: # set to gui devices apply(func, pargs, kargs) sys.stdin, sys.stdout = streams elif mode == ONIDLE: def runner(func, pargs, kargs, streams=streams): apply(func, pargs, kargs) sys.stdin, sys,stdout = streams sys.stdout.after_idle(apply, runner, pargs, kargs) elif mode == THREAD: def runner(func, pargs, kargs, streams=streams): apply(func, pargs, kargs) sys.stdin, sys,stdout = streams thread.start_new_thread(runner, (func, pargs, kargs)) else: assert 0, 'Bad run mode' def redirectGuiShellCmd(command, mode=THREAD, currBox=None): input = os.popen(command, 'r') output = currBox or GuiOutput(Toplevel()) def reader(input, output): # show shell command while 1: # output in a popup line = input.readline() # text box widget if not line: break output.write(line) if mode == BLOCK: reader(input, output) elif mode == ONIDLE: output.after_idle(reader, input, output) elif mode == THREAD: thread.start_new_thread(reader, (input, output)) else: assert 0, 'Bad run mode' class GuiOutputBox(Toplevel): def __init__(self, parent=None): Toplevel.__init__(self, parent) # single window model self.box = GuiOutput(self) # embed an output frame def runShellCmd(self, cmd, mode=THREAD): redirectGuiShellCmd(cmd, mode, self.box) def runFunction(self, func, pargs, kargs, mode=BLOCK): redirectGuiFunc(func, pargs, kargs, mode, self.box) def write(self, line): self.box.write(line) # # self-test logic # def _selfTest(): # an enclosing gui app def interact(number=5): # runs a non-gui function print 'Starting interact' # and non-gui shell commands while 1: try: input = raw_input('Enter value: ') print input, '*', number, 'is:', eval(input) * number except EOFError: break except: print 'Bad number--try again' for i in xrange(100000000): if i % 10000 == 0: print i # stress the cpu print 'Done' for mode in (THREAD, ONIDLE, BLOCK): Button(text='Shell ' + mode, command=lambda m=mode: redirectGuiShellCmd('ls *.py', m)).pack(fill=X) for mode in (THREAD, ONIDLE, BLOCK): Button(text='Func ' + mode, command=lambda m=mode, i=interact: redirectGuiFunc(i, (4,), {}, m)).pack(fill=X) def existingBox1(): win = Toplevel() box = GuiOutput(win) box.pack() Button(win, text='OK', command=win.destroy).pack() # erase window box.write('--Hello GuiStreams world--\n') redirectGuiShellCmd('ls *.py', BLOCK, box) box.write('--Second command--\n') redirectGuiShellCmd('ls *.txt', BLOCK, box) box.write('--Command finished--\n') def existingBox2(interact=interact): win = GuiOutputBox() Button(win, text='OK', command=win.destroy).pack() # erase window win.write('--Hello GuiStreams world--\n') win.runShellCmd('ls *.py', BLOCK) win.write('--Second command--\n') win.runShellCmd('ls *.txt', BLOCK) win.write('--Function--\n') win.runFunction(interact, (), {}) win.write('--Command finished--\n') Button(text='Shell box1', command=existingBox1).pack(fill=X) Button(text='Shell box2', command=existingBox2).pack(fill=X) mainloop() if __name__ == '__main__': _selfTest()