我正在用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)
任何想法如何实现这一目标?
我已经扩展了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提供一些语法糖来轻松创建事件并将它们传递给中间人.