Как написать оболочку Scala для javax.swing.Timer - PullRequest
2 голосов
/ 26 июля 2011

Я бы хотел использовать таймер в приложении 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 ]

5 голосов
/ 26 июля 2011

Канонический способ сделать это состоит в том, чтобы ввести псевдоним в верхней части того, на что вы хотите сослаться (обычно self, если это уже не принято):

class ScalaTimer(time: Int) extends Component {
  self =>
  val t = ...
    publish(new scala.swing.event.ActionEvent(self))
  ...
4 голосов
/ 26 июля 2011

Не работает, потому что это относится к ActionListener, а не к классу ScalaTimer.

Том прав: вы можете использовать ScalaTimer.this.

(Моя IDE немедленно помечает «Отсутствующие аргументы для метода Timer(Int, ActionListener)», что кажется немного странным, поскольку я не вызывал метод.)

Timer(Int, ActionListener) - конструктор Timer, который вы вызвали .Вам нужно написать extends javax.swing.Timer(constructor_args).Конечно, аргументы конструктора могут зависеть от аргументов конструктора для ScalaTimer.

2 голосов
/ 26 июля 2011

Вы сможете достичь этого в Java следующим образом: ScalaTimer.this

В Scala, наверное, тоже самое

1 голос
/ 24 сентября 2011

Мне пришлось недавно заняться этим, и мне кажется, что это работает:

// 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())
  })
}

Вы также можете переопределить другие методы, чтобы обеспечить лучшую инкапсуляцию, но это работает как есть.

0 голосов
/ 25 марта 2014

Простая обертка:

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}}}
...