What is an expected method of connecting view and model in JavaFX?
Binding?
Suppose I want to make positioning in database with the following controls:
I have data (recordset) object in memory and it's properties are bindable. I.e. they are notifying when current record changes and when the number of records changes.
I want user to be able position inside recordset both with slider and text field.
How to accomplish that? There is no numeric spin in JavaFX, so how to bind text, slider and recordset object (three ends) together? Is it possible?
I cannot give an authoritative answer since I don't work for Oracle nor am I some JavaFX-pert but I usually construct the controller with an instance of the model and in the initialize method of the controller I create the bindings between the controls' properties and the model's properties.
To your concrete problem I have a lame but working solution. Lame because I can't figure out how to use the low-level binding API and I use two properties on the model. Here's how :
FXML :
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.TextField?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<Slider GridPane.columnIndex="0" fx:id="slider" min="0" max="99"/>
<Label GridPane.columnIndex="1" text="Record" />
<TextField fx:id="textfield" GridPane.columnIndex="2"/>
</GridPane>
Main.java :
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import sample.Models.Model;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
final Model model = new Model();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("sample.fxml"));
loader.setControllerFactory(new Callback<Class<?>, Object>() {
@Override
public Object call(Class<?> aClass) {
return new Controller(model);
}
});
GridPane root = (GridPane) loader.load();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
}
Controller.java :
package sample;
import javafx.beans.binding.DoubleBinding;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import sample.Models.Model;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
private final Model model;
public Controller(Model model) {
this.model = model;
}
@FXML
public Slider slider;
@FXML
public TextField textfield;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
slider.valueProperty().bindBidirectional(model.pageProperty());
textfield.textProperty().bindBidirectional(model.pageTextProperty());
}
}
Model.java :
package sample.Models;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
public class Model {
private IntegerProperty pageProperty;
private StringProperty pageTextProperty;
public Model() {
pageProperty = new SimpleIntegerProperty(2);
pageProperty.addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2) {
int value = pageProperty.get();
//System.out.println("Page changed to " + value);
if (Integer.toString(value).equals(pageTextProperty.get())) return;
pageTextProperty.set(Integer.toString(value));
}
});
pageTextProperty = new SimpleStringProperty("2");
pageTextProperty.addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s2) {
try {
int parsedValue = Integer.parseInt(observableValue.getValue());
if (parsedValue == pageProperty.get()) return;
pageProperty().set(parsedValue);
} catch (NumberFormatException e) {
// too bad
}
}
});
}
public int getPage() {
return pageProperty.get();
}
public void setPage(int page) {
pageProperty.set(page);
}
public IntegerProperty pageProperty() {
return pageProperty;
}
public String getPageText() {
return pageTextProperty.get();
}
public void setPageText(String pageText) {
pageTextProperty.set(pageText);
}
public StringProperty pageTextProperty() {
return pageTextProperty;
}
}