在Jython中,是否有一种Python式的方式向EDT提交方法



在Python中,人们习惯于做

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

在Jython中,我发现如果我想向EDT提交一种方法,我必须去

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

显然,然后您有关于传递参数等的所有随之而来的问题。我只是想知道是否有一种更快速、更 Python 式的方式来向 EDT 提交方法?

@lvc

谢谢。。。是的,事实上我明白了...其实成语

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

是我习惯使用的一个,只是为了停止用一次性子类化实例的类名弄乱命名空间。

事实上,我已经得到了sthg来减轻任务

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 关于它。

后:

  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成语:

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

因此,您提交一种方法,然后是可选的参数...然后,此方法最终使用有问题的参数在 EDT 中运行。 无需创建可运行变量...

当然,另一种可能性是从SwingWorker中分类...那么你就不会有这种有点麻烦的"双队列"安排(即 WorkerThread 队列,以及 EDT 自己的队列,它交付给 process())...但是你必须在doInBackground中有一个相当不优雅的循环(使用sleep())...

会对人们的观点感兴趣

要意识到的主要事情是,SwingUtilities.invokeAndWait期望单方法接口的实例,因为Java没有一流的函数。如果不使用除 SwingUtilities 以外的其他东西,该位是不可避免的,具有更 Python 的接口,用于此功能。

如果您打算使用该特定 API,您仍然可以避免使用包装器函数。只需做:

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

包装函数的唯一原因是能够使用闭包将函数传入来调用run;您仍然可以通过将函数传递到RunnableClass.__init__中并存储它来执行此操作:

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

请注意,func不应该self作为第一个参数 - 因为它是实例而不是类上的属性,因此它不会被视为方法。

根据您的编辑 - 将func传递到 RunnableClass.__init__ 中的要点是它不再需要是一次性子类 - 您将要运行的每个 func 都不需要一个 Runnable 子类,只需要一个RunnableClass实例。该类本身是从 Python 习语到 Java 的通用适配器,因此您不需要围绕它的函数来完成相同的工作。

这意味着您的runToMessageTree可能如下所示:

def runToMessageTree(self, method, *args, **kwargs):
    if SwingUtilities.isEventDispatchThread():
       method(*args, **kwargs)
    else:
       SwingUtilities.invokeAndWait(RunnableClass(method, *args, **kwargs))

最新更新