与scala swing应用程序中的actor交互

Dan*_*itz 9 swing scala actor

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

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

通过单击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)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

  sender ! Progress(value) // whenever progress is made
Run Code Online (Sandbox Code Playgroud)

我通过在gui中创建一个单独的actor来解决这个问题.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
          }
        }
      }
    }
  } 
Run Code Online (Sandbox Code Playgroud)

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

  reactions += {
    case ButtonClicked(`startButton`) => actor ! ForwardToApplication(Process(file))
  }
Run Code Online (Sandbox Code Playgroud)

这段代码工作得很好.我的问题:有更简单的方法吗?简单地使用我的应用程序消息的反应机制是很好的:

  reactions += {
    case Progress(value) => progressBar.value = value
  }
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*itz 6

我已经扩展了gerferras的想法,使我的应用程序成为一个swing.Publisher.以下类充当a swing.Reactor和a之间的中介Actor.

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)))
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

implicit val intermediator = Intermediator(application)
listenTo(intermediator, button)

reactions += {
  case ButtonClicked(`button`) => Send(Process(file))
  case Receive(Progress(value)) => progressBar.value = value
}
Run Code Online (Sandbox Code Playgroud)

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