2011-07-26 145 views
2

我试图延长javax.swing.Timer中不被认可,但它只有一个构造函数,它是斯卡拉 - 方法构造

Timer(int delay, ActionListener listener) 

我不希望我在斯卡拉子取一个Java ActionListener在它的构造函数中。我在very old thread中读到:“没有办法直接调用超类的构造函数;你必须传递你自己类的主构造函数”,所以它看起来像我坚持在主构造函数中使用ActionListener。所以我增加了一个辅助构造这样的:

case class TimerEvent (source: AnyRef) extends swing.event.Event 

class ScalaTimer2 (delay: Int, listener: java.awt.event.ActionListener) 
     extends javax.swing.Timer(delay, listener) with swing.Publisher { 
    outer => 
    def this(delay: Int) = { 
    this(delay, new java.awt.event.ActionListener { 
     def actionPerformed(e: java.awt.event.ActionEvent) { 
     publish(TimerEvent(outer)) // <-- publish not recogonized 
     } 
    }) 
// publish(TimerEvent(outer)) // <-- publish recognized here 
    } 
} 

不过,我得到一个编译错误error: not found: value publish ...为什么?以及如何解决?

+2

对于那些寻找到这个问题,意识到问题的SI-4842,其崩溃的编译器:https://issues.scala-lang.org/browse/SI-4842 –

回答

5

实际上有两个问题:在构造函数完成之前,publishouter都不可用。斯卡拉似乎有一个规则,this实例不能在辅助构造函数中引用,直到主构造函数完成。例如,下面将编译失败:

class Foo (x: Unit) { def this() { this(println(this)) } } 

而不是辅助构造,如何对伴随对象上定义工厂方法?

object ScalaTimer2 { 
    def apply(delay: Int): ScalaTimer2 = { 
    lazy val ret: ScalaTimer2 = new ScalaTimer2(delay, new java.awt.event.ActionListener { 
     def actionPerformed(e: java.awt.event.ActionEvent) { 
     ret.publish(TimerEvent(ret)) 
     } 
    }) 
    ret 
    } 
} 

注意的ret前方基准需要使用lazy val,而不是仅仅val的。推测actionPerformed在构造函数返回前不会被调用,否则ret将由于无限递归而无效。

1

下面是我在这个特殊情况下找到的解决方法:发送一个虚拟的ActionListener,然后删除并替换为真实的。

class ScalaTimer2 private (delay: Int, listener: java.awt.event.ActionListener) 
     extends javax.swing.Timer(delay, listener) with swing.Publisher { 
    outer => 

    def this(delay: Int) = 
    this(delay, new java.awt.event.ActionListener { 
     def actionPerformed(e: java.awt.event.ActionEvent) { } // dummy 
    }) 
    removeActionListener(listener) 

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

编辑:另一招:使主构造private所以,有没有机会尝试误用自己的ActionListener建设。

编辑2:或通过在签名中传递匿名ActionListener来完全避免辅助构造函数。

编辑3-解决! :我刚刚在Javadoc中读到传递给构造函数的ActionListener可以为null!所以我们实际上需要的是:

class ScalaTimer2 (delay: Int) extends Timer(delay, null) with Publisher { 
    outer => 
    addActionListener(new ActionListener { 
    def actionPerformed(e: ActionEvent) { 
     publish(new TimerEvent(outer)) 
    } 
    }) 
}