0

I'm creating a program to ping many computer labs at once. On the home UI there there are images that are either red or green based on if all of the computers are pingable or not. When I call the pingAllLabs method it changes them to red or green correctly, but all at once at the end rather than as each is finished.

This stackOverflow answer is very similar but I can't/don't know how to implement it

Here is the code that does the pinging. In the Lab class it creates an arraylist of strings of the PC names that are broken.

@FXML
public void pingAllLabs() throws IOException{
    for (int  i = 0;i<list.listOfLabs.size();i++{
       list.listOfLabs.get(i).printBroke(fileName);
       updateImages(list.listOfLabs.get(i),i);
    }
}

And here is the code that actually changes the images. It retrieves the arrayList of broken pc's from the lab that is sent to it and if the list is not empty it changes the image in an arraylist of images to red or if the list is empty it changes it to green.

    @FXML
public void updateImages(Lab lab,int i){

    Image red = new Image("RedComp.png");
    Image green = new Image("GreenComp.png");

    ArrayList<String> list = lab.getBrokenList();

    if (!list.isEmpty()){
        images.get(i).setImage(red);
        System.out.println("Setting "+lab.getName()+" to red");
    }
    else{
        System.out.println("Setting to green");
        images.get(i).setImage(green);

    }

}
Jeremy
  • 41
  • 1
  • 5
  • Use `Timeline`. https://stackoverflow.com/questions/9966136/javafx-periodic-background-task – SedJ601 Nov 27 '18 at 22:34
  • It is still quite unclear what is going on. Am I right to say that there are multiple labs, and each lab has multiple computers, and each computer (with its pingable state) is represented by an image on the GUI? If this is so, then now the GUI updates all computers in a *single* lab all at once, or all computers in *all* labs? – Jai Nov 28 '18 at 02:01

1 Answers1

0

For this method here block here

public void pingAllLabs() throws IOException{
    for (int  i = 0;i<list.listOfLabs.size();i++{
       list.listOfLabs.get(i).printBroke(fileName);
       updateImages(list.listOfLabs.get(i),i);
    }
}

Make the following change

public void pingAllLabs() throws IOException{

    new Thread(() -> {
           for (int  i = 0;i<list.listOfLabs.size();i++) {
           list.listOfLabs.get(i).printBroke(fileName);
           updateImages(list.listOfLabs.get(i),i);
           }
       }).start();

    }
}

And change this block

 if (!list.isEmpty()){
        images.get(i).setImage(red);
        System.out.println("Setting "+lab.getName()+" to red");
    }
    else{
        System.out.println("Setting to green");
        images.get(i).setImage(green);

    }

make the following change

 if (!list.isEmpty()){
        Platform.runLater( () -> images.get(i).setImage(red))
        System.out.println("Setting "+lab.getName()+" to red");
    }
    else{
        System.out.println("Setting to green");
         Platform.runLater( () -> images.get(i).setImage(green))

    }

So now you wont block the UI thread and also allow the updates to be done asynchronously.

Insights

The problem is akin to the question you linked, you are running the for loop on the JavaFx Application thread, which causes the model changes not to be rendered immediately but only after you return from pingAllLab() which returns only after updateImages() returns which contains the loop. The above code runs the image adding logic on a different thread and then posts the updates to the UI event queue using Platform.runLater().

Hence, whenever you write code that affects the UI in some way, use Platform.runLater()

Ryotsu
  • 786
  • 6
  • 16