Francesco Valla
Francesco Valla

Reputation: 214

Change the image in ImageView in javaFX

I'm looking for an example where is needed to change dinamically the image x.png when an certain variable x getting value 1 into y.png, when this variable going back to 0 restore the old image. If this is possible , how? thanks for help

im trying whith this code but have no succes...

this is my controller class

public class FXMLDocumentController implements Initializable {

@FXML
private ImageView myImage;

@Override
public void initialize(URL url, ResourceBundle rb) {
    Random random = new Random();


    while (true) { // <-- this is the problem how i can do that without while(true)??
        int x = random.nextInt(1);
        if (x == 0) {
            Image image = new Image(getClass().getResource("x.png").toExternalForm());
            myImage.setImage(image);
        }
        if (x == 1) {
            Image image = new Image(getClass().getResource("y.png").toExternalForm());
            myImage.setImage(image);
        }

    }

}

}

Upvotes: 0

Views: 3944

Answers (3)

DVarga
DVarga

Reputation: 21829

A quite robust solution is to use a binding between an IntegerProperty and the imageProperty of the ImageView:

ImageView im = new ImageView();
IntegerProperty intValue = new SimpleIntegerProperty();
List<Image> images = Arrays.asList(new Image(getClass().getResource("aa.png").toString()),
        new Image(getClass().getResource("bb.png").toString()));

im.imageProperty().bind(Bindings.createObjectBinding(() -> images.get(intValue.getValue()),
    intValue));

The images are put into a List (or array, or any indexable container), and then the binding returns the Image on the corresponding index.


To make the images flickering, you can start a new Thread:

Task<Void> task = new Task<Void>() {
    @Override
    protected Void call() throws Exception {
        Random random = new Random();
        while (true) {
            Thread.sleep(50);
            intValue.set(random.nextInt(images.size()));
        }
    }
};

Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();

Upvotes: 2

Tobi
Tobi

Reputation: 182

If I understood you correctly, you want to switch images whenever the value of an integer-variable changes. You could put your x in a SimpleIntegerProperty and add a Listener to it.

SimpleIntegerProperty xProperty = new SimpleIntegerProperty();
xProperty.addListener((observable, oldValue, newValue) -> {
    if (newValue.intValue() == 0) {
        myImage.setImage(image1);
    }
    if (newValue.intValue() == 1) {
        myImage.setImage(image2);
    }
});
xProperty.set(random.nextInt());

Each time you call set on xProperty, your listener gets triggered.

As pointed out in a comment to my answer, you shoud not reload the images each time - so I removed that code and just used the variables image1 and image2. You could intiialize them in the constructor.

Upvotes: 2

Groostav
Groostav

Reputation: 3239

So I do not believe your problem is in JavaFX presentation logic but rather in the blocking-nature of the source-data your trying to consume. In this sense I suggest you take-up @Tobi in his view code, and add the following class:

import javafx.application.Platform;
import java.util.concurrent.Executors;


class XAdapter {

  private static final ExecutorService blockableThread = Executors.newCachedThreadPool();

  public void pushChangesTo(IntegerProperty notifier){
    blockableThread.submit(() -> {

      int newX = random.nextInt(); //insert your long running call here. 

      Platform.runLater(() -> {
        notifier.setValue(newX);
        pushChangesTo(notifier)
      });
    });
  }
}

Then you can modify your Document like this:

public class FXMLDocumentController {

  //...

  IntegerProperty xProperty = new SimpleIntegerProperty();
  private final XAdapter adapter = new XAdapter()

  @Override public void initialize(){
    adapter.pushChangesTo(xProperty)
  }
}

note: this is java concurrency, and its very easy to get concurrency wrong. You might consider spending some time with a book like Java Concurrency In Practice to udnerstand why what you were doing was problematic, and what the exact purpose of executors and Platform.runLater is. There are a great many better ways to do this, and the solution I wrote here might well not be acceptable to a project lead. In particular, you probably want to mark blockableThread as being a daemon thread.

notice the last attributed author of the book I linked you to, and the author of the class Executors, are the same person.

Upvotes: 0

Related Questions