Search code examples
scalajavafxscalafx

Base Class constructor not being called in JFXApp


package pGrid
package pUIFx
import pUtil._    

object DevAppFx extends AppFx
{
  println("Begining DevFxApp object constructor in package pGrid.pUIFx")   
  //devStart 
}

package pGrid
package pUIFx
import pGeom._
import pGrid.pDev._

import scalafx.application._
import scalafx.application.JFXApp._
import scalafx.scene._
import scalafx.scene.paint._

class AppFx extends JFXApp with DevTr
{   
  println("Creating stage")
  stage =  new PrimaryStage
  {
    x = 3850
    y = 200
    width = 1000
    height = 800          
    scene = new Scene
  }
  def openEFO(de: DescEFlatOne): Unit =
  {
    println("def in AppFx")
    stage.scene = ScrEditFx(stage, de)            
  }
}

The DevAppFx object constructor runs, including the println ("Beginning ...

The class AppFx constructor does not run including the println ("creating stage"). The openEFO method can be called but the stage variable is null.

Edit this is a simplification. There will be a lot more functionality in DEVAppFx and AppFx, so its important to be able to keep the functionality separate.


Solution

  • I think the issue here is that scalafx.application.JXFApp is a class that extends the scala.DelayedInit trait. As such, some Scala magic happens under the hood: see the scala.DelayedInit docs for more. Unfortunately, DelayedInit is buggy and plays havoc with sub-class initialization/construction code - such as your AppFx class not executing its constructor.

    There's no easy solution to this, I'm afraid. Until the DelayedInit behavior is resolved, or until we find a better way to initialize ScalaFX, your best bet is to merge DevAppFx and AppFx into a single object, which should work as expected.

    For example:

    package pGrid
    package pUIFx
    import pGeom._
    import pGrid.pDev._
    
    import scalafx.application._
    import scalafx.application.JFXApp._
    import scalafx.scene._
    import scalafx.scene.paint._
    
    object AppFx extends JFXApp with DevTr
    {   
      println("Creating stage")
      stage =  new PrimaryStage
      {
        x = 3850
        y = 200
        width = 1000
        height = 800          
        scene = new Scene
      }
      // Relocate DevAppFx init here...
      println("Begining DevFxApp object constructor in package pGrid.pUIFx")   
      //devStart 
      def openEFO(de: DescEFlatOne): Unit =
      {
        println("def in AppFx")
        stage.scene = ScrEditFx(stage, de)            
      }
    }
    

    UPDATE:

    I did some more digging around, and scalafx.application.JFXApp didn't do a great job of implementing the semantics of the scala.DelayedInit trait. In essence, it was only storing the construction/initialization code of the class/object at the bottom of the inheritance hierarchy, and dropping everything else. For further details, there is a ScalaFX bug report for this issue.

    So, in your example, the construction code for the object DevAppFx was replacing the construction code for your class AppFx, instead of storing both, resulting in the symptoms you observed.

    I've committed a patch to the default and SFX-8 branches of ScalaFX on Google Code, which you're free to utilize. Alternatively, if you're prepared to wait a few weeks, the next updates published to the Sonatype OSS to have the patch will be 1.0.0-R9 (for the JavaFX 2 equivalent) and 8.0.0-R5 (for the JavaFX 8 equivalent).

    This patch should allow your original code to run unmodified. If you get a chance to try it out, let me know how you get on...