0

在 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()() )

显然你有关于传递参数等的所有伴随问题。我只是想知道是否可能有一种更快捷、更 Pythonesque 的方式来向 EDT 提交方法?

@lvc

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

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

是我习惯性地使用的一种,只是为了停止使用一次性子类实例的类名来混淆命名空间。

事实上,我有一些事情可以减轻任务

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

所以你提交一个方法,然后是可选的 args ...然后这个方法最终在 EDT 中运行,使用有问题的 args。无需创建 Runnables...

当然,另一种可能性是从 SwingWorker 子类化......然后你不会有这种稍微麻烦的“双队列”安排(即 WorkerThread 队列和 EDT 自己的队列,它传递给 process())......但是那么你必须在doInBackground中有一个相当不雅的循环(使用sleep())......

会对人们的意见感兴趣

4

1 回答 1

1

要实现的主要事情是SwingUtilities.invokeAndWait需要一个单方法接口的实例,因为 Java 没有一流的函数。如果不使用SwingUtilities具有更多 Pythonic 接口的其他东西来实现此功能,那么这一点是无法避免的。

如果您决定使用该特定 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是它不再需要是一次性子类 -对于要运行的每个 func,您RunnableClass.__init__不需要一个子类,只需一个. 该类本身是从 Python 习语到 Java 的通用适配器,因此您不需要围绕它的函数来完成相同的工作。RunnableRunnableClass

这意味着你runToMessageTree可以看起来像这样:

def runToMessageTree(self, method, *args, **kwargs):
    if SwingUtilities.isEventDispatchThread():
       method(*args, **kwargs)
    else:
       SwingUtilities.invokeAndWait(RunnableClass(method, *args, **kwargs))
于 2012-06-17T13:23:41.713 回答