2

I have FXML application with model, view and controller. My view is in .fxml file and I have Text there like this

<Text fx:id="position" text="None" GridPane.columnIndex="1" GridPane.rowIndex="3">
   <font>
      <Font name="System Bold" size="18.0" />
   </font>
</Text>

My Controller look like this

public class Controller{

   @FXML
   private Text position;

   public void updatePosition(String text){
      position.setText(text);
   }
}

In my Model, there I have String variable, which is changing throughout all my project. Model look like this

public class Model {

   public String position = "None";

   public  String getPosition() {
      return tactic;
   }

   public void setPosition(String position) {
      this.position = position;
   }
}

There are another classes in my project, which call setPositon method and update variable position. Is there a way how to change Text in my view, when someone change position variable in Model class?

M. Barabas
  • 89
  • 3
  • 11

1 Answers1

3

You need to observe the model. The easiest way to do this in JavaFX is to use JavaFX properties to represent the data.

public class Model {

    private final StringProperty position = new SimpleStringProperty("None");

    public StringProperty positionProperty() {
        return position ;
    }

    public final String getPosition() {
        return positionProperty().get();
    }

    public final void setPosition(String position) {
        positionProperty().set(position);
    }
}

Now you can simply bind the text's textProperty() to the model's positionProperty(), and if the model's position is changed, the text will automatically update:

public class Controller{

   @FXML
   private Text position;

   private Model model ;

   public void initialize() {
       position.textProperty().bind(model.positionProperty());
   }

   // ...
}

The only tricky part now is to make sure the controller has a reference to the correct model instance. The best way to do this is to provide a constructor for the controller taking a model:

public class Controller {

   @FXML
   private Text position;

   private final Model model ;

   public Controller(Model model) {
       this.model = model ;
   }

   public void initialize() {
       position.textProperty().bind(model.positionProperty());
   }

   // ...
}

The problem now is that the default mechanism for creating controllers via the FXMLLoader relies on a zero-argument constructor, so it won't work. So you need to remove the fx:controller attribute from the FXML file and set the controller "by hand":

Model model = new Model(); // or just reference to existing model...

FXMLLoader loader = new FXMLLoader(getClass().getResource("View.fxml"));
loader.setController(new Controller(model));
Parent root = loader.load();
// ...

model.setPosition("Left"); // will update text in view

See Passing Parameters JavaFX FXML for more ways to pass the model (or other data) to the controller.

Also see the related question Applying MVC With JavaFx

James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thanks a lot :) It works well. One more thing - when I create instance of Model like this `Model model = new Model();` I have to use this instance in another class, so it has to be static, because I canot make instanse of class which extends Application. It there a way how to not use static instance of model ? – M. Barabas Jan 06 '18 at 20:42
  • @M.Barabas If you create it in, for example, the `start()` method, you should be able to pass it to any controller (or other class) that needs it, since the `start()` method is the entry point for the entire application. That can sometimes get a bit complex, in which case I would recommend using a dependency injection framework (such as Guice, Weld, or Spring). You might also be interested in [afterburner.fx](http://afterburner.adam-bien.com/) (essentially a JavaFX-specific DI framework). – James_D Jan 06 '18 at 20:45