Axim
Axim

Reputation: 332

How do I dynamically change the image in an ImageView (JavaFX)?

I'm trying to implement a validation check for the contents of a TextField, displaying the validity as an icon next to it. However it doesn't seem to change the image. Here is the code I have so far, I've stripped out anything not related to the problem I'm experiencing.

Here's the view class:

package mypackage.view;

import mypackage.model.Foo;

// JavaFX imports

public class MyView extends VBox {

  private final Foo model;
  private final MyPresenter presenter;

  HBox tokenValidationbox;
  TextField tokentxt;
  ImageView isValidimg;

  public MyView(Foo model) {
    this.model = model;

    initFieldData();
    layoutForm();

    this.presenter = new MyPresenter(model, this);
  }

  private void initFieldData() {
    tokenValidationbox = new HBox();
    tokentxt = new TextField();
    isValidimg = new ImageView();
  }

  private void layoutForm() {
    tokenValidationbox.getChildren().addAll(tokentxt, isValidimg);
    this.getChildren().add(tokenValidationbox);
  }
}

And this is the presenter class that contains the logic:

package mypackage.view;

import mypackage.model.Foo;

// JavaFX imports

public class MyPresenter {

  private final Foo model;
  private final MyView view;

  public MyPresenter(Foo model, MyView view) {
    this.model = model;
    this.view = view;

    attachEvents();
  }

  private void attachEvents() {
    view.tokentxt.setOnAction((ActionEvent event) -> {
      view.isValidimg.setImage(new Image(validationImage(view.tokentxt.getText())))
    });
  }

  public String validationImage(String token) {
    String img = "dialog-error.png";
    if(isValid(token)) img = "emblem-default.png";
    return getClass().getClassLoader().getResource(img).toExternalForm();
  }

  private static boolean isValid(String token) {
    // snip
  }
}

As I understand this should check whether the entered token is valid whenever something is changed in the text field, and then load the corresponding image to display, however the image is not showing up.

emblem-default.png and dialog-error.png are located in the project resources folder and can be loaded statically (i.e. if I put an Image constructor inside the ImageView when initializing it, it works just fine)

Upvotes: 0

Views: 1760

Answers (1)

fabian
fabian

Reputation: 82531

Add a ChangeListener to the text property instead. onAction is only triggered, when Enter is pressed or similar.

Furthermore I recommend not recreating the images every time:

private static final Image VALID_IMG = new Image(MyPresenter.class.getClassLoader().getResource("emblem-default.png").toExternalForm());
private static final Image INVALID_IMG = new Image(MyPresenter.class.getClassLoader().getResource("dialog-error.png").toExternalForm());

public Image validationImage(String token) {
    return isValid(token) ? VALID_IMG : INVALID_IMG;
}

view.tokentxt.textProperty().addListener((observable, oldValue, newValue) -> {
    view.isValidimg.setImage(validationImage(newValue));
});

You could also use a Binding for this:

view.isValidating.imageProperty().bind(Bindings.createObjectBinding(() -> validationImage(view.tokentxt.getText()), view.tokentxt.textProperty()));

Which would update the image even before the text is modified.

Upvotes: 1

Related Questions