from __future__ import print_function import os import sys import Queue import plac_core from Tkinter import Tk from ScrolledText import ScrolledText from plac_ext import Monitor, TerminatedProcess class TkMonitor(Monitor): """ An interface over a dictionary {taskno: scrolledtext widget}, with methods add_listener, del_listener, notify_listener and start/stop. """ def __init__(self, name, queue=None): Monitor.__init__(self, name, queue) self.widgets = {} @plac_core.annotations(taskno=('task number', 'positional', None, int)) def add_listener(self, taskno): "There is a ScrolledText for each task" st = ScrolledText(self.root, height=5) st.insert('end', 'Output of task %d\n' % taskno) st.pack() self.widgets[taskno] = st @plac_core.annotations(taskno=('task number', 'positional', None, int)) def del_listener(self, taskno): del self.widgets[taskno] @plac_core.annotations(taskno=('task number', 'positional', None, int)) def notify_listener(self, taskno, msg): w = self.widgets[taskno] w.insert('end', msg + '\n') w.update() def start(self): 'Start the mainloop' self.root = Tk() self.root.title(self.name) self.root.wm_protocol("WM_DELETE_WINDOW", self.stop) self.root.after(0, self.read_queue) try: self.root.mainloop() except KeyboardInterrupt: print('Process %d killed by CTRL-C' % os.getpid(), file=sys.stderr) except TerminatedProcess: pass def stop(self): self.root.quit() def read_queue(self): try: cmd_args = self.queue.get_nowait() except Queue.Empty: pass else: getattr(self, cmd_args[0])(*cmd_args[1:]) self.root.after(100, self.read_queue)