In Jython, is there a Pythonesque way to send a method to EDT?

In python is used to execute

def runTaskInNonEDT(): pass tRunTask = threading.Thread( target = runTaskInNonEDT ) tRunTask.start() 

In Jython, I found that if I want to send a method to EDT, I need to go

 def makeRunnableClass(): class RunnableClass( Runnable ): def run( rSelf ): pass return RunnableClass SwingUtilities.invokeAndWait( makeRunnableClass()() ) 

obviously you have all the related questions about passing parameters, etc. I'm just wondering if there could be a faster, more Pythoneque way to send a method to EDT?

@lvc

thank you ... yes I really understand that ... really an idiom

 def makeSthgClass(): class SthgClass(): pass return SthgClass 

is the one that I use, as a rule, to stop cluttering the namespace with the cool class names of the subclass.

I really got sthg to make the task easier

 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 is nothing satisfactory to Pythonic about this.

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 # ie 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 # ie 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 arguments ... and this method then runs in EDT using the appropriate arguments. No runnables should be created ...

Of course, another possibility is to subclass from SwingWorker ... then you would not have this slightly disturbing "double queue" (ie WorkerThread Queue and your own EDT queue that delivers process ()) ... but then you have there should be a rather inelegant loop (using sleep ()) in doInBackground ...

People watching will be interesting

0
python multithreading jython event-dispatch-thread
Jun 17 '12 at 13:11
source share
1 answer

The main thing to understand is that SwingUtilities.invokeAndWait expects an instance of an interface with a single method, because Java does not have first-class functions. This bit cannot be avoided without using anything other than SwingUtilities , with a more Pythonic interface for this function.

If your heart is set to use this particular API, you can still avoid using the wrapper function. Just do:

 class RunnableClass(Runnable): def run(self): pass SwingUtilities.invokeAndWait(RunnableClass()) 

The only reason to use a wrapper function is to use the pass function to call run with closures; you can still do this by passing the function to RunnableClass.__init__ and saving it:

 class RunnableClass(Runnable): def __init__(self, func): self._func = func def run(self): self._func() 

Note that func should not accept self as the first parameter - since its attribute is in the instance and not in the class, it is not considered as a method.

For your editing - the func transfer point in RunnableClass.__init__ is that it no longer needs to be a subclass with one shot - you do not need one Runnable subclass for each function, re-launch, just one instance of RunnableClass . The class itself is a universal adapter from the Python idiom to Java, so you don't need a function around it to do the same job.

This means your runToMessageTree might look like this:

 def runToMessageTree(self, method, *args, **kwargs): if SwingUtilities.isEventDispatchThread(): method(*args, **kwargs) else: SwingUtilities.invokeAndWait(RunnableClass(method, *args, **kwargs)) 
+1
Jun 17 '12 at 13:23
source share
— -



All Articles