如何为javax.swing.Timer编写Scala包装器

时间:2011-07-26 05:40:57

标签: java swing scala timer wrapper

我想在Scala Swing应用程序中使用计时器。我可以使用Java版本,只是这意味着我必须实现ActionListener接口。我宁愿使用Scala Publishers / Reactors模型来保持一致性,所以我可以得到listenTo计时器。

这是我试过的:

class ScalaTimer(time: Int) extends Component {
  val t = new javax.swing.Timer(time, new java.awt.event.ActionListener {
    def actionPerformed(e: java.awt.event.ActionEvent) {
      publish(new scala.swing.event.ActionEvent(this))
    }
  })
  def start() {t.start()}
  def stop() {t.stop()}
  // etc

}

不起作用,因为this引用了ActionListener而不是ScalaTimer类。

另外我可能不应该扩展Component ...我试过这个因为我得到了Publisher / Reactor功能,但它没有用。我应该这样做吗?如果是这样,我是否需要包含其他特征,以及如何知道我必须实施哪些方法?

 class ScalaTimer extends javax.swing.Timer with Publisher {

(我的IDE立即标记“缺少方法Timer(Int,ActionListener)的参数”,这似乎有点奇怪,因为我没有调用方法。)

5 个答案:

答案 0 :(得分:5)

这样做的规范方法是在你要引用的东西的顶部引入一个别名(通常是self,除非已经采用了):

class ScalaTimer(time: Int) extends Component {
  self =>
  val t = ...
    publish(new scala.swing.event.ActionEvent(self))
  ...

答案 1 :(得分:4)

  

不起作用,因为它指的是ActionListener而不是ScalaTimer类。

汤姆是对的:您可以使用ScalaTimer.this

  

(我的IDE立即标记“缺少方法Timer(Int, ActionListener)的参数”,这似乎有点奇怪,因为我没有调用方法。)

Timer(Int, ActionListener)Timer的构造函数,您已调用。你需要写extends javax.swing.Timer(constructor_args)。当然,构造函数参数可能依赖于ScalaTimer的构造函数参数。

答案 2 :(得分:2)

您可以在Java中实现这一点: ScalaTimer.this

在Scala中可能是相同的

答案 3 :(得分:1)

我最近也必须解决这个问题,这似乎对我有用:

// First create a TimerEvent since using an ActionEvent necessitates that ScalaTimer extend
// Component, which isn't ideal as the OP indicated 
case class TimerEvent() extends scala.swing.event.Event

// extending javax.swing.Timer by and large avoids the hassle of writing wrapper methods
class ScalaTimer(val delay0:Int) extends javax.swing.Timer(delay0, null) with Publisher {

  // to mimic the swing Timer interface with an easier-to-user scala closure
  def this(delay0:Int, action:(()=>Unit)) = {
    this(delay0)
    reactions += {
      case TimerEvent() => action()
    }
  }

  addActionListener(new java.awt.event.ActionListener {
    def actionPerformed(e: java.awt.event.ActionEvent) = publish(TimerEvent())
  })
}

您还可以覆盖其他方法以提供更好的封装,但这样可以正常运行。

答案 4 :(得分:0)

简单包装:

import scala.swing.event.Event,
       scala.swing.Reactions,
       java.awt.event.ActionEvent,
       javax.swing.AbstractAction


case class Tick(source: Timer) extends Event
case class Timeout(source: Timer) extends Event

abstract class Timer {
  private val timer = this
  private var counter = 0
  private val tick = new AbstractAction(){def actionPerformed(e:ActionEvent) = {
    reactions(Tick(timer))
    if(_repeats > 0){
      counter -= 1
      if(counter == 0){run = false; reactions(Timeout(timer))}}}}
  val reactions: Reactions = new Reactions.Impl
  private var _interval = 1000
  def interval:Int = _interval
  def interval_=(i:Int):Unit = {_interval = i; peer.setDelay(i)}
  private var _repeats = -1
  def repeats:Int = _repeats
  def repeats_=(i:Int):Unit = {_repeats = i; counter = i}
  private var _run = false
  def run:Boolean = _run
  def run_=(f:Boolean):Unit = { _run = f; runStop(f)}
  private def runStop(f:Boolean) = f match{
    case true => {
      counter = _repeats
      if(counter != 0){peer.start()}else{reactions(Timeout(timer))}}
    case false => peer.stop()}
  val peer = new javax.swing.Timer(_interval, tick); peer.setRepeats(true)}

使用:

import scala.swing._

object Main extends Frame {
  //
  override def closeOperation() = {System.exit(0)}
  visible = true
  //
  def main(a:Array[String]):Unit = {
    val t = new Timer{
      interval = 500 //In milliseconds
      repeats = 10   //Repeats 10 times
      reactions += {case Tick(_) => println("tick")
                    case Timeout(_) => println("timeout")}
      run = true}}}