2011-07-26 189 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)) 
    } 
    }) 
}