Search code examples
javascalajavafxscalafx

Can't move TextFlow inside a new scene


In my ScalaFX project I want to create a separate help page for the user in which he/she can click a topic which causes instructions to appear next to the clickable topics.

Problem is that when I create the new scene for the help page no matter what I do I can't move the TextFlow around. It stays in the same place in top of the ListView. See picture for reference.

 helpMenu.onAction = (ae: ActionEvent) => {
    val helpStage = new Stage()
    helpStage.setTitle("A wild help stage appears!")
    val helpScene = new Scene(scene.width.get * 0.6, scene.height.get * 0.8) {
      val listView        = new ListView(List.tabulate(3) { n => "Option " + (n + 1) })
      val text1           = new Text("This is fine\n*zips coffee*\nThis is all fine.")
      val textFlow        = new TextFlow(text1)
      /*
       * Nothing below changes where the text appears in the new scene.
       */
      textFlow.layoutX  <== listView.width.get
      textFlow.alignmentInParent_=(Pos.TOP_RIGHT)
      textFlow.alignmentInParent_=(Pos.BASELINE_CENTER)
      text1.alignmentInParent_=(Pos.BASELINE_CENTER)

      listView.prefHeight <== scene.height.get * 0.4
      content.addAll(listView, textFlow)

    }
    helpStage.setScene(helpScene)
    helpStage.show()
    helpScene.listView.onMouseClicked = (le: MouseEvent) => {
      val item = helpScene.listView.selectionModel.apply.getSelectedItem
    }
  }

What I want to know is how can I orient text next to the list view? The goal is to make the instructions to appear there. My plan was to use

helpScene.listView.onMouseClicked = (le: MouseEvent) => { val item = helpScene.listView.selectionModel.apply.getSelectedItem }

to this purpose since we can easily determine what was clicked inside the list.

enter image description here


Solution

  • I think the problem here is that you need to add the ListView and TextFlow elements to a container that will control how they are laid out. In the code below, I'm using an HBox for that purpose, which puts the two side-by-side. (There are other options in the scalafx.scene.layout package, such as VBox, BorderPane, etc. This tutorial, for the older JavaFX 2 release, might help give you a better appreciation of the topic.)

    After that, I'm a little unclear what you're trying to achieve, but what I think you're trying to do is to show different text in the TextFlow depending upon which item in the ListView is selected. If that's the case, then the following example addresses that by using a change of selection to trigger a change in TextFlow content. (If this isn't what you had in mind, can you elaborate on your requirements?)

    Also, I've simplified some of your code to use ScalaFX's properties (as opposed to JavaFX's getters & setters).

    onAction = (ae: ActionEvent) =>  {
      val helpStage = new Stage() {
    
        // Make room for the list view and the text flow.
        width = 400
    
        // Set the help text to the default.
        val defaultText = "Please make\na selection"
        val helpText = new Text(defaultText)
    
        // Help for each option in the list view. If a key doesn't match, then the default
        // text is displayed.
        val optionText = Map(
          "Option 1" -> "This is\nsome help for\nOption 1",
          "Option 2" -> "And this is\nsome help for\nOption 2",
          "Option 3" -> "Finally, this is\nsome help for\nOption 3",
        ).withDefaultValue(defaultText)
    
        // Title the stage and set the scene...
        title = "A wild help stage appears!"
        scene = new Scene {
    
          val listView = new ListView(List.tabulate(3) { n => "Option " + (n + 1) }) {
    
            // Change the help text when the selection changes.
            selectionModel().selectedItem.onChange {(_, _, selected) =>
              helpText.text = optionText(selected);
            }
          }
    
          // Add the help text to the text flow.
          val textFlow = new TextFlow(helpText)
    
          // Put list view and text flow elements side-by-side.
          content = new HBox(listView, textFlow)
        }
      }
      helpStage.show()
    }