After a few hours work I have managed to understand how to create a custom component using javafx and Gluons Scene Builder. How does one add a new property for that component which will appear in the scene builder properties menu so that the property value can be entered at design time.
You need to subclass something, most likely an implementation of Parent
, Region
or Pane
. From there you can load the FXML which was generated by whatever you have done in Scene Builder
.
Example:
public class MyComponent extends VBox {
private final StringProperty foo = new SimpleStringProperty();
public MyComponent {
final Parent root = (Parent) FXMLLoader.load(getClass().getResource(fxmlPath));
getChildren().add(root);
}
public final StringProperty fooProperty() { return foo; }
public final String getFoo() { return foo.get(); }
public final void setFoo(String foo) { this.foo.set(foo); }
}
This may produce an extra container, one being MyComponent
, the other being the root node of the FXML. To prevent this, use FXMLLoader.setRoot()
.
It seems like you have an extra obstacle - the controller which has the main logic is decoupled with MyComponent
.
There are many ways to do this:
You can pass in the reference of MyComponent
into the controller.
public class MyController {
/* Your controller stuff */
private MyComponent component;
public final void setComponent(MyComponent component) {
// You can bind your controller properties to fooProperty here
}
}
Then when loading the FXML in MyComponent
, you get the reference of the controller and manually call setComponent()
.
This method directly exposes the properties of the controller in MyComponent
public class MyComponent extends VBox {
// Other stuff
private MyController controller;
public MyComponent {
// Original stuff
this.controller = loader.getController();
}
public final StringProperty fooProperty() {
assert controller != null; // If you loaded correctly this assertion should be valid
return controller.fooProperty();
}
public final String getFoo() { return fooProperty().get(); }
public final void setFoo(String foo) { fooProperty().set(foo); }
}
This method simply combines MyComponent
and MyController
into a single class. You would need FXMLLoader.setController(this)
.
The advantage is you have direct access to everything. The bad thing is, some people would say this violates MVC.