Coming from WPF and XAML, going back to JavaFX I'm having quite a hard time with bindings. In general, I get the gist and binding properties of a model class to GUI-elements do work if I code them in Java. But there's so much boilerplate code, it's really exhausting.
In the past I've avoided FXML and always built my GUIs in plain Java. Now I want to see what I've missed. Being already familiar with XAML provided an easier entry to FXML but I'm having issues with bindings. There's a post from someone with a similar background: How to do binding in FXML, in JavaFX 2?
To the "problem" itself: Again, coming from WPF, it seems like a whole lot of overhead and boilerplate to get a simple string binding from code to the GUI and I wonder if there's a easier, more modern or more convenient way of binding properties.
I haven't found much in regards of bindings and FXML, other than old posts and more recent answers (as of 2020) stating that the state of FXML still isn't great after all this time.
At this point I'm no longer sure what to do exactly. Writing a lot of boilerplate code for so many properties to just get a proper binding... Might actually be more feasible to update GUI components directly to reduce code (e.g. set the text property on the label itself by passing data from the model)?
Update with example (sorry for not including this in the first place); note that I'm using Lombok to generate getters and setters with annotations to already reduce the amount of boilerplate code:
Simple model class:
public class Model {
@Getter @Setter
private StringProperty someString = new SimpleStringProperty("test");
}
Simplified controller:
public class Controller {
@FXML
public Label myLabel;
@FXML
public Label myOtherLabel;
@Getter @Setter
private StringProperty someString = new SimpleStringProperty("test");
@Getter @Setter
private Model model = new Model();
public void init() {
// if I wouldn't use binding within FXML I would do the following:
myLabel.textProperty().bind(someString);
myOtherLabel.textProperty().bind(model.getSomeString());
}
public void onButtonClick(ActionEvent e) {
someString.set("clicked");
model.getSomeString().set("clicked");
}
}
Simplified FXML view:
<VBox>
<Text>Some text</Text>
<Label fx:id="myLabel" text="${controller.someString}"/>
<Label fx:id="myOtherLabel" text="${controller.model.someString}"/>
</VBox>
Correction to my initial statement: I was actually missing a detail, so I think I figured out why it doesn't work. Looks like I would always need four items for one binding to work:
// the actual property holding the data
private StringProperty someString = new SimpleStringProperty("Test");
// a method to return the above property
public StringProperty someStringProperty() {
return someString;
}
// a getter for the actual text of the property
public String getSomeString() {
return someString.get();
}
// a setter for the property string (optional)
public void setSomeString(String text) {
someString.set(text);
}
All I'm doing is generating some data that needs to be displayed on the GUI. Manually writing up to four members per property just for a binding in FXML seems a lot.
The alternative is binding in code with someProperty.bind(someOtherProperty)
for each property I wish to display. At the same time, I could just write someLabel.setText(someString);
and I'd be done with it.
Creating the bindings in code (as seen above) also comes with a drawback; In case I wanted to swap out (or re-generate) the model, the bindings won't update. I will have to re-use one instance of the model and set it's contents in order not to break the bindings.
Just to give another example where I'm coming from which might help understanding why I raised this issue. In WPF/XAML you would just have the following:
public class Model
{
public string SomeString { get; set; }
}
public partial class View ...
{
public Model DataModel { get; set; }
}
In the XAML file:
<Label Text = "{Binding DataModel.SomeString}" />
... then set the Model object as data context, done. It's probably not fair to compare both frameworks like this, and this isn't meant to complain and to be like "WPF is so much better bla bla". Again, just trying to explain where I come from.
TLDR; should I bite the bullet and go for a ton of boilerplate to have a nice FXML binding or do it the "primitive" way and set GUI contents directly, sparing myself all that additional code?
As of now, to me personally, it seems it would be more viable to ditch FXML and build the GUI purely in Java as it seems like it would drastically reduce the amount of code, since even if you define your GUI in FXML, you'd probably have to double down on re-defining controls in your controller anyway to have access to them.