0

In JavaFX, how do you model the following:

I show a List of Customers in a Scene. On the left side there is a table on the right side (contentPane) the currently select customer's details are shown.

(Relevant part of) Main-Controller:

@jfxf.FXML
protected def newButtonPressed(): Unit =
{
    contentPane.getChildren.clear
    contentPane.getChildren.add(FXMLLoader.load(GUILoader.load("customers/form.fxml")))
}

There is a Button to add a new Customer. Upon clicking this button instead of opening a Popup, I replace the "details"-part of the scene and add a form there.

Now for this form (designed - like the rest of the GUI - in the SceneBuilder and saved as .fxml) I use another controller.

class Form extends Main with jfxf.Initializable
{
    @jfxf.FXML
    private var foreNameTextField: jfxsc.TextField = _
    @jfxf.FXML
    private var lastNameTextField: jfxsc.TextField = _
    @jfxf.FXML
    private var ageTextField: jfxsc.TextField = _

    override def initialize(url: URL, resourceBundle: ResourceBundle): Unit =
    {

    }

    @jfxf.FXML
    protected def ok(): Unit =
    {
        // TODO validation
        val newPerson = new Person(-1, foreNameTextField.getText, lastNameTextField.getText, ageTextField.getText.toInt)
       // Save to DB
       // Close whole form
    }
} 

When I'm done with filling in a new customer's detail I click on another button (that calls ok()) and save it to a database.

What I want to do now is close the form and replace it with the detail-form.

Something like calling a protected method in the main-controller like:

protected def clearDetails(): Unit =
{
   contentPane.getChildren.clear
   contentPane.getChildren.add(savedOldDetails)
}

won't work of course. (Will throw a runtime-exception because there is no contentpane in the sub/form-controller (even if I make it protected)

In Qt (C++) I'd use signals/slots and connect them accordingly.

Seems like in JavaFX there is nothing the like. How am I supposed to share such information?

Do I need to create a "super-controller" for the contentPane?

1 Answers1

0

(I don't know Scala, so I'll write this in Java, hope that is ok).

You can define an observable property in the Form controller, and observe it when you load the form from the main controller:

public class Form implements Initializable {

    private final ObjectProperty<Person> person = new SimpleObjectProperty<>(null);

    public ObjectProperty<Person> personProperty() {
        return person ;
    }

    public final Person getPerson() {
        return personProperty().get();
    }

    public final void setPerson(Person person) {
        personProperty().set(person);
    }

    // ... code you had before...

    @FXML
    protected void ok() {
        Person person = new Person(-1, foreNameTextField.getText(), lastNameTextField.getText(), ageTextField.getText());
        // save to DB...
        personProperty().set(person);
    }
}

Now in your main controller, load the form as follows:

@FXML
protected void newButtonPressed() {
    contentPane.getChildren().clear();
    FXMLLoader loader = new FXMLLoader(getClass().getResource("customers/form.fxml"));
    Parent form = loader.load();
    Form formController = loader.getController();
    formController.personProperty().addListener((obs, oldPerson, newPerson) {
        if (newPerson != null) {
            // clear form, etc, e.g.
            clearDetails();
        }
    });
    contentPane.getChildren().add(form);
}
James_D
  • 201,275
  • 16
  • 291
  • 322