问题描述
在Python中,一种习惯是
In Python one is used to doing
def runTaskInNonEDT():
pass
tRunTask = threading.Thread( target = runTaskInNonEDT )
tRunTask.start()
在Jython中,我发现如果要向EDT提交方法,我必须走
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()() )
很显然,您接下来会遇到所有与传递参数有关的问题,等等.我只是想知道是否可能有一种更简单,更Python化的方法向EDT提交方法?
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
@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()() )
所以你可以去
def doSthg():
pass
self.runToMessageTree( doSthg )
...但是没有令人满意的Pythonic.
... but there's nothing satisfyingly Pythonic about it.
稍后:
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是一个非常简单的经典python习语:
Ẁ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
,因此您提交了一个方法,后跟可选的args ...,然后该方法最终使用有问题的args在EDT中运行.无需创建Runnable ...
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...
当然,另一种可能性是从SwingWorker继承子类...那么您将不会有这种稍微麻烦的双队列"安排(即,WorkerThread队列和EDT自己的队列,该队列传递给process()). ..但是然后您必须在doInBackground中有一个相当不优雅的循环(使用sleep())...
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...
会对人们的观点感兴趣
推荐答案
要实现的主要事情是SwingUtilities.invokeAndWait
需要一个单方法接口的实例,因为Java没有一流的功能.如果不使用SwingUtilities
以外的其他东西(具有更多Pythonic界面)来实现此功能,则无法避免这一点.
The major thing to realise is that SwingUtilities.invokeAndWait
expects an instance of a single-method interface because Java doesn't have first-class functions. That bit isn't avoidable without using something other than SwingUtilities
, with a more Pythonic interface, for this functionality.
如果您愿意使用特定的API,则仍然可以避免使用包装器功能.只要做:
If your heart is set on using that particular API, you can still avoid having the wrapper function. Just do:
class RunnableClass(Runnable):
def run(self):
pass
SwingUtilities.invokeAndWait(RunnableClass())
使用包装函数的唯一原因是能够使用传递函数使用闭包在run
中调用;您仍然可以通过将函数传递到RunnableClass.__init__
并将其存储来完成此操作:
The only reason for using the wrapper function is to be able to use pass a function in to invoke in run
using closures; you can still do this by passing the function into RunnableClass.__init__
and storing it:
class RunnableClass(Runnable):
def __init__(self, func):
self._func = func
def run(self):
self._func()
请注意,func
不应将self
作为第一个参数-由于它是实例而不是类的属性,因此不会被视为方法.
Note that func
shouldn't take self
as a first parameter - since its an attribute on the instance rather than on the class, it doesn't get treated as a method.
根据您的编辑-将func
传递到RunnableClass.__init__
的意义在于,它不再是一次性的子类-您不需要为每个函子使用Runnable
的一个子类.重新运行,只是RunnableClass
的一个实例. 类本身是从Python惯用语到Java惯用语的通用适配器,因此您不需要围绕它的函数即可完成相同的工作.
Per your edit - the point of passing func
into RunnableClass.__init__
is that it doesn't need to be a one-shot subclass anymore - you don't need one subclass of Runnable
for every func you're going to run, just one instance of RunnableClass
. The class itself is a generic adapter from the Python idiom to the Java one, so you don't need a function around it to do the same job.
这意味着您的runToMessageTree
可能如下所示:
This means your runToMessageTree
can look like this:
def runToMessageTree(self, method, *args, **kwargs):
if SwingUtilities.isEventDispatchThread():
method(*args, **kwargs)
else:
SwingUtilities.invokeAndWait(RunnableClass(method, *args, **kwargs))
这篇关于在Jython中,是否有Pythonesque方式将方法提交给EDT?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!