【问题标题】:Interacting with actors in scala swing applications在 scala swing 应用程序中与参与者交互
【发布时间】:2011-06-04 16:04:23
【问题描述】:

我正在用 scala 编写一个小应用程序。应用程序处理简单的日志文件。因为处理需要一些时间,所以我决定让我的应用程序核心扩展 Actor。

class Application extends Actor {
  def react() {
    loop {
      react {
        case Process(file) => // do something interesting with file...
      }
    }
  }
}

通过单击 gui 中的按钮触发日志文件的处理。 gui 使用 scala swing。

object Gui extends SimpleSwingApplication {
  val application = new Application().start()

  def top = new MainFrame {
    val startButton = new Button

    reactions += {
      case ButtonClicked(`startButton`) => application ! Process(file)
    }
  }
}

现在,应用程序核心需要通知 gui 当前进度。

  sender ! Progress(value) // whenever progress is made

我通过在 gui 中创建一个单独的演员解决了这个问题。 Actor 在 edt 线程中执行。它侦听来自应用程序核心的消息并更新 gui。

  object Gui extends SimpleSwingApplication {
    val actor = new Actor {
      override val scheduler = new SchedulerAdapter {
        def execute(fun: => Unit) { Swing.onEDT(fun) }
      }
      start()

      def act() {
        loop {
          react {
            case ForwardToApplication(message) => application ! message
            case Progress(value) => progressBar.value = value
          }
        }
      }
    }
  } 

由于应用程序核心需要知道消息的发送者,我也使用这个actor将消息从gui转发到应用程序核心,使我的actor成为新的发送者。

  reactions += {
    case ButtonClicked(`startButton`) => actor ! ForwardToApplication(Process(file))
  }

这段代码工作得很好。我的问题:有没有更简单的方法来做到这一点?对我的应用程序消息简单地使用反应机制会很好:

  reactions += {
    case Progress(value) => progressBar.value = value
  }

任何想法如何实现这一目标?

【问题讨论】:

    标签: swing scala actor


    【解决方案1】:

    我已经扩展了 gerferras 的想法,即让我的应用程序成为 swing.Publisher。以下类充当swing.ReactorActor 之间的中介。

    import actors.Actor
    import swing.Publisher
    import swing.event.Event
    import swing.Swing.onEDT
    
    case class Send(event: Any)(implicit intermediator: Intermediator) {
      intermediator ! this
    }
    case class Receive(event: Any) extends Event
    
    case class Intermediator(application: Actor) extends Actor with Publisher {
      start()
    
      def act() {
        loop {
          react {
            case Send(evt) => application ! evt
            case evt => onEDT(publish(Receive(evt)))
          }
        }
      }
    }
    

    现在我的反应可以包括挥杆事件和应用程序事件。

    implicit val intermediator = Intermediator(application)
    listenTo(intermediator, button)
    
    reactions += {
      case ButtonClicked(`button`) => Send(Process(file))
      case Receive(Progress(value)) => progressBar.value = value
    }
    

    注意case class Send 如何提供一些语法糖来轻松创建事件并将它们传递给中介。

    【讨论】:

    • 我认为这是一个很好的解决方案。也许我应该得到一个赞成票作为回报;)
    • 我认为你在对ButtonClicked的反应中缺少intermediator !
    • @geferra intermediator ! 调用在 case class Send 的构造函数内。 intermediator 通过隐式参数传递。我赞成您的回答,因为它为我自己的解决方案提供了灵感。
    • 嘿,我只是想感谢您提供的解决方案。看起来正是我一直在寻找的 :)
    【解决方案2】:

    也许这更简单,但不知道它是否更好。您可以在每次需要处理文件时创建一个匿名 Actor,而不是让您的应用程序后端成为 Actor:

    reactions += {
      case ButtonClicked(`startButton`) => application.process(file, { v: Int => Swing.onEDT(progressBar.value = v) })
    }
    

    对于进度更新部分,可以在每次有新的进度时,传递一个回调给要执行的process方法:

    import scala.actors.Actor.actor
    
    def process(f: File, progress: Int => Unit) {
      actor {
        // process file while notifying the progress using the callback
        progress(n)
      }  
    }
    

    或者(尚未测试)您可以将您的应用程序设为scala.swing.Publisher,而不是每次都使用回调,发布和事件。所以代码可能是:

    listenTo(startButton, application) //application is a Publisher
    
    reactions += {
      case ButtonClicked(`startButton`) => application.process(file)
      case Progress(v) => progressBar.value = v
    }
    

    在应用程序中:

    import scala.actors.Actor.actor
    
    def process(f: File) {
      actor {
        // process file while notifying the progress using an scala.swing.event.Event
        publish(Progess(n))
      }  
    }
    

    【讨论】:

    • 您对回调的第一个想法可行,但我认为如果我需要传递其他消息,我与演员的方法更具可扩展性。
    • 第二种方法呢?您的应用程序将在某种程度上与 Swing 前端相关联,但我认为这还不错,如果我正确阅读了您的问题,那么这就是您最后所要求的
    • 我已经尝试了您的第二种方法并对其进行了一些扩展。看看我自己的回答这个解决方案的样子。
    猜你喜欢
    • 2011-03-24
    • 2011-09-02
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    • 2017-03-25
    • 2012-06-09
    • 2012-11-25
    • 1970-01-01
    相关资源
    最近更新 更多