In Python one is used to doing
def runTaskInNonEDT():
pass
tRunTask = threading.Thread( target = runTaskInNonEDT )
tRunTask.start()
In Jython, I find that if I want to submit a method to the EDT I have to go
def makeRunnableClass():
class RunnableClass( Runnable ):
def run( rSelf ):
pass
return RunnableClass
SwingUtilities.invokeAndWait( makeRunnableClass()() )
obviously you then have all the attendant questions about passing parameters, etc. I was just wondering if there might be a snappier, more Pythonesque way of submitting a method to the EDT?
@lvc
thanks... yes in fact I get that... in fact the idiom
def makeSthgClass():
class SthgClass():
pass
return SthgClass
is one I use habitually just to stop cluttering up the namespace with one-shot subclassed instances' classnames.
I have in fact got sthg to lighten the task
def runToMessageTree( self, method, *args, **kvargs ):
if SwingUtilities.isEventDispatchThread():
method( *args, **kvargs )
else:
def makeRunnableClass():
class RunnableClass( Runnable ):
def run( self ):
method( *args, **kvargs )
return RunnableClass
SwingUtilities.invokeAndWait( makeRunnableClass()() )
so you can go
def doSthg():
pass
self.runToMessageTree( doSthg )
... but there's nothing satisfyingly Pythonic about it.
later:
class EDTWorkerThread( WorkerThread ):
def __init__( ewt_self, name ):
super( EDTWorkerThread, ewt_self ).__init__( name )
class EDTWorker( SwingWorker ):
def doInBackground(self ):
check_event_thread( False )
while True:
method_call_elements = ewt_self.input_queue.get()
if method_call_elements is None: # "poison pill"
break
self.super__publish( [ method_call_elements ])
ewt_self.input_queue.task_done()
return
def process( self, chunks ):
check_event_thread( True )
for chunk in chunks:
assert type( chunk ) is list
assert chunk # i.e. must have at least one element!
# check that first item is callable
assert hasattr( chunk[ 0 ], "__call__" )
method_call_elements = chunk
method_args = method_call_elements[ 1 : ]
method_call_elements[ 0 ]( *method_args )
ewt_self.input_queue.task_done()
ewt_self.swing_worker = EDTWorker()
def run( self ):
self.swing_worker.execute()
ẀorkerThread is a very simple, classic python idiom:
class WorkerThread( threading.Thread ):
def __init__( self, *args, **kvargs ):
threading.Thread.__init__( self, *args, **kvargs )
self.input_queue = Queue()
def send( self, item ):
assert type( item ) is list
assert item # i.e. must have at least one element!
# check that first item is callable
assert hasattr( item[ 0 ], "__call__" )
self.input_queue.put( item )
def close( self ):
self.input_queue.put( None )
self.input_queue.join()
def run( self ):
while True:
method_call_elements = self.input_queue.get()
if method_call_elements is None: # "poison pill"
break
method_args = method_call_elements[ 1 : ]
method_call_elements[ 0 ]( *method_args )
self.input_queue.task_done()
self.input_queue.task_done()
return
so you submit a method followed by optional args ... and this method then ends up being run in the EDT, using the args in question. No Runnables have to be created...
Of course the other possibility is to subclass from SwingWorker... then you wouldn't have this slightly troubling "double-queue" arrangement (i.e. WorkerThread Queue, and the EDT's own queue, which delivers to process())... but then you have to have a rather inelegant loop (using sleep()) in doInBackground...
Would be interested in people's views