[英]How to write a Scala wrapper for javax.swing.Timer
I'd like to use a timer in a Scala Swing application. 我想在Scala Swing应用程序中使用计时器。 I can use the Java version, only it means I have to implement the ActionListener interface.
我可以使用Java版本,只是这意味着我必须实现ActionListener接口。 I'd rather use the Scala Publishers / Reactors model for consistency, so I can have things that
listenTo
the timer. 我宁愿使用Scala Publishers / Reactors模型来保持一致性,所以我可以把东西
listenTo
计时器。
Here's what I tried: 这是我试过的:
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
}
Doesn't work because this
refers to the the ActionListener rather than the ScalaTimer class. 不起作用,因为
this
指的是ActionListener而不是ScalaTimer类。
Also I probably shouldn't be extending Component
... I tried this because I get the Publisher / Reactor functionality, but it doesn't really make sense. 另外我可能不应该扩展
Component
...我试过这个因为我得到了Publisher / Reactor功能,但它没有用。 Should I do something like this instead? 我应该这样做吗? If so, are there other traits I need to include, and how do I know which methods I have to implement?
如果是这样,我是否还需要包含其他特征,如何知道我必须实施哪些方法?
class ScalaTimer extends javax.swing.Timer with Publisher {
(My IDE immediately flags "Missing arguments for method Timer(Int, ActionListener)" which seems a bit weird since I haven't invoked a method.) (我的IDE立即标记“缺少方法Timer(Int,ActionListener)的参数”,这似乎有点奇怪,因为我没有调用方法。)
The canonical way to do this is to introduce an alias at the top of the thing you want to refer to (usually self
unless that's already taken): 这样做的规范方法是在你要引用的东西的顶部引入一个别名(通常是
self
除非已经采用):
class ScalaTimer(time: Int) extends Component {
self =>
val t = ...
publish(new scala.swing.event.ActionEvent(self))
...
Doesn't work because this refers to the the ActionListener rather than the ScalaTimer class.
不起作用,因为它指的是ActionListener而不是ScalaTimer类。
Tom is correct: you can use ScalaTimer.this
. 汤姆是对的:你可以使用
ScalaTimer.this
。
(My IDE immediately flags "Missing arguments for method
Timer(Int, ActionListener)
" which seems a bit weird since I haven't invoked a method.)(我的IDE立即标记“缺少方法
Timer(Int, ActionListener)
”,这似乎有点奇怪,因为我没有调用方法。)
Timer(Int, ActionListener)
is the constructor of Timer
, which you have invoked. Timer(Int, ActionListener)
是的构造Timer
,你已经调用。 You need to write extends javax.swing.Timer(constructor_args)
. 您需要编写
extends javax.swing.Timer(constructor_args)
。 Of course, the constructor arguments may depend on constructor arguments for ScalaTimer
. 当然,构造函数参数可能依赖于
ScalaTimer
构造函数参数。
You would be able to achieve this in Java thus: ScalaTimer.this 你可以用Java实现这一点:ScalaTimer.this
It's probably the same in Scala 在Scala中它可能是相同的
I had to tackle this recently as well and this seems to work for me: 我最近也必须解决这个问题,这似乎对我有用:
// 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())
})
}
You could also override other methods to provide for better encapsulation, but this is functional as is. 您还可以覆盖其他方法以提供更好的封装,但这是实用的。
Simple wrapper: 简单的包装:
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)}
Use: 采用:
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}}}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.