Search code examples
scalajavafxjavafx-8scalafx

Adding a SubScene to the center of a BorderPane in ScalaFX


The main layout of my ScalaFX 8 application consists of a BorderPane. The top attribute contains a menu whereas bottom contains something similar to a status bar. My goal is to display a component for viewing 3D objects in the center of the BorderPane (acting as a SubScene).

stage = new PrimaryStage {
  scene = new Scene(900, 900, true, SceneAntialiasing.Balanced) {
    root = new BorderPane {
      top = createMenu // creates a menu inside of a VBox
      center = createViewer // should create a subscene inside of whatever is needed
      bottom = createStatusBar // creates a status bar inside of a VBox
    }
  }
}

I'm trying to create a minimal working example with a SubScene that only consists of black background and a simple sphere, no more, no less. The SubScene should use the whole space that is available in the center of BorderPane and resize accordingly. Unfortunately, I can't make it work.

Since the size of a SubScene is fixed, I assume it is necessary to embed the SubScene in another container (which is able to resize automatically) and bind the dimensions of the SubScene to the dimensions of the container around it.

def createViewer = {
  val bp = new BorderPane
  val subScene: SubScene = new SubScene(bp, 200, 200, true, SceneAntialiasing.Balanced) {
    fill = Color.Black
    width <== bp.width
    height <== bp.height
    content = new Sphere(3) { material = new PhongMaterial(Color.Red) }
    camera = new PerspectiveCamera(true) { ... }
  }
  bp.center = subScene
  subScene
}

The result looks like this:

enter image description here

Two obvious problems:

  • The SubScene keeps the fixed size from its constructor. In neither "maximizes" in the center of the outer BorderPane, nor does it do anything when the window gets resized
  • There is the red dot, but the bottom right corner of the SubScene is not black (?)

My assumption is that I have some problems understanding what the root element of the SubScene really is and what it does. I found another thread for JavaFX with a similar problem, this solution distinguishes between the root element of the SubScene (I'm not sure where that element comes from) and the Pane but I couldn't apply it to my case. Any help is appreciated. Thanks.


Solution

  • the idea here is to get the read only properties for the top level scene there is probably a more elegant way to do this, but this works

    scene = new Scene(900, 900, true, SceneAntialiasing.Balanced) {
       // these are read only properties for the scene
       var tmpw = this. width
       var tmph =  this. height
    
       root = new BorderPane {
    
         top = new HBox {
           content = new Label {
             text = "menu"
           }
         }
    
         center = createView(tmpw,  tmph)
    
       }
     }
       width onChange show
       height onChange show
    

    }

    the idea here is to bind the read only properties to the properties of the subscene, then the subscene will re-size there is probably a way to avoid the 'this' key-word. I have tested this and the subscene re-sizes with the parent scene. I have omitted the PerspectiveCamera code block as you did not include what you were using

    def createView(boundWidth : ReadOnlyDoubleProperty, boundHeight : ReadOnlyDoubleProperty):         BorderPane = {
    
      new BorderPane {
    
          center = new SubScene(boundWidth.get(), boundHeight.get(), true, SceneAntialiasing.Balanced) {
          fill = Color.BLACK
          content = new Sphere(3) { material = new PhongMaterial(Color.RED) }
          camera = new PerspectiveCamera(true)
           // bind the subscene properties to the parents 
            this.width.bind(boundWidth.add(-200))
            this.height.bind(boundHeight.add(-200))
        }
    
      }
    
    }