Difficulty Moving Multiple Circles Through JavaFx's GridPane

134 Views Asked by At

I am currently facing challenges while working with GridPane. My objective is to move a specified number of generated circles through the cells of a GridPane. I have 5 GridPane and in every one of them consists of 10 vertical cells, and I aim to move the circles one cell at a time, starting from 0 and progressing until the last cell in every GridPane, where the circle should disappear.

I have successfully moved a single circle, but I'm encountering difficulties when handling multiple circles and orchestrating their movement in a sequential line. Additionally, I'm seeking guidance on adjusting the speed of the circles individually. I would like to incorporate a speed factor, so if there is a slow-moving circle, it will cause a delay in the overall movement of the line.

Here is the relevant code snippet:

package phase1;

import javafx.animation.*;
import Classes.Person;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class Phase1 extends Application {
    ArrayList<Circle> PEOPLE;
    private List<Circle> objects;
    private Timer timer;
    private boolean isRowEmpty(GridPane gridPane, int rowIndex) {
        for (javafx.scene.Node node : gridPane.getChildren()) {
            Integer nodeRowIndex = GridPane.getRowIndex(node);
            if (nodeRowIndex != null && nodeRowIndex.intValue() == rowIndex) {
                return false;
            }
        }
        return true;
    }

    
    @Override
    public void start(Stage stage) throws InterruptedException, IOException {

        // Create the root container (AnchorPane)
        Parent fxmlRoot = new FXMLLoader().load(getClass().getResource("/PHASE.fxml"));
        // Create the controller and move the circles
        Phase1Controller controller = new Phase1Controller();


        Group root = new Group(); //Creating a Group
        root.getChildren().add(fxmlRoot);
        GridPane graid1 = (GridPane) fxmlRoot.lookup("#Grid2");
        objects = new ArrayList<>();
        //PEOPLE = Phase1Controller.show_circles(fxmlRoot, 10);
        ArrayList<Person> people = Main1.generatePeople(5);
        Circle c1 = people.get(0).circle;
        Circle c2 = new Circle(22.5,Color.RED);

        timer = new Timer();
        graid1.add(c1,0,0);
        int RowIndex = 0;

        AtomicInteger rowIndex = new AtomicInteger(0);
        AtomicBoolean ss = new AtomicBoolean(true);
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                Platform.runLater(() -> {
                    int currentRowIndex = rowIndex.getAndIncrement();
                    if (currentRowIndex >0){
                        //graid1.getChildren().set(currentRowIndex-1,c2);

                        }

                        // Add the node to the new row
                    graid1.getChildren().remove(c1);

                    // Add the node to the new row
                    graid1.add(c1, 0, currentRowIndex);
                    int pp = graid1.getRowConstraints().size();
                    System.out.println(pp);
                    if(pp == currentRowIndex){ graid1.getChildren().remove(c1); timer.cancel();}

                });


            }
        }, 0, 1000);// Run every 1 second




            // Create a scene and set it to the stage
            Scene scene = new Scene(root);
        stage.setTitle("Team 1");
        stage.setResizable(true); // Display the Resizable
        stage.setScene(scene);
        stage.show();

        }

    public static void main(String[] args) {
        launch();
    }


    }

And here is a gif from the GUI, illustrating only one circle in motion:

enter image description here

1

There are 1 best solutions below

2
On

You are asking more than one question. Keep your post at one question per post. Here is something that can maybe help you move your circles.

I would use Timeline over Timer.

Timeline Example

import java.util.ArrayList;
import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;

public class Mavenproject3 extends Application {
    final int ROW_COUNT = 8;
    final int COLUMN_COUNT = 1;

    
    @Override
    public void start(Stage stage){
        
        GridPane gridPane = new GridPane();
        gridPane.setGridLinesVisible(true);
        RowConstraints rowConstraints = new RowConstraints(100, 100, 100);
        ColumnConstraints columnConstraints = new ColumnConstraints(100, 100, 100);
        for(int i = 0; i < ROW_COUNT; i++)
        {
            gridPane.getRowConstraints().add(rowConstraints);
        }
        
        for(int i = 0; i < COLUMN_COUNT; i++)
        {
            gridPane.getColumnConstraints().add(columnConstraints);
        }
        
        Circle c1 = new Circle(22.5,Color.BLUE);
        Circle c2 = new Circle(22.5,Color.RED);
        Circle c3 = new Circle(22.5,Color.YELLOW);
        Circle c4 = new Circle(22.5,Color.GREEN);
        Map<Circle, Integer> circleMap = new LinkedHashMap();        
        circleMap.put(c1, -1);
        circleMap.put(c2, -1);
        circleMap.put(c3, -1);
        circleMap.put(c4, -1);
        List<Circle> keys = new ArrayList(circleMap.keySet());
        
        AtomicInteger addCircleCounter = new AtomicInteger();
        AtomicInteger cycleCounter = new AtomicInteger();
        
        Timeline oneSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(1), (ActionEvent event) -> {
            //Moving circles
            if(cycleCounter.get() > 0 && cycleCounter.get() < circleMap.size() + ROW_COUNT)
            {
                for(Circle key : keys)
                {
                    if(circleMap.get(key) > -1)
                    {
                        //System.out.println("Moving Circle " + key.getFill()+ " to " + circleMap.get(key));
                        if(circleMap.get(key) >= ROW_COUNT - 1 )
                        {
                            gridPane.getChildren().remove(key);
                        }
                        else
                        {
                            circleMap.merge(key, 1, Integer::sum);
                            gridPane.getChildren().remove(key);                        
                            gridPane.add(key, 0, circleMap.get(key));
                        }
                    }
                }
            }
            
            //Add Circle to GridPane
            if(addCircleCounter.get()< circleMap.size())
            {
                //System.out.println("Add Circle " + keys.get(addCircleCounter.get()).getFill()+ " to GridPane!");
                gridPane.add(keys.get( addCircleCounter.get()), 0, 0);   
                circleMap.merge(keys.get( addCircleCounter.get()), 1, Integer::sum);
            }  
           
            cycleCounter.getAndIncrement();
            addCircleCounter.getAndIncrement();
        }));
        oneSecondsWonder.setCycleCount(Timeline.INDEFINITE);
        oneSecondsWonder.play();
        
        Button btnDecreaseSpeed = new Button("<");
        btnDecreaseSpeed.setOnAction((ActionEvent event) -> {
            double rate = oneSecondsWonder.getRate();
            if (rate > 1) {
                oneSecondsWonder.setRate(oneSecondsWonder.getRate() - 1);
                System.out.println("Speed: " + oneSecondsWonder.getRate());
            }
        });
        
        Button btnIncreaseSpeed = new Button(">");
        btnIncreaseSpeed.setOnAction((ActionEvent event) -> {
            double rate = oneSecondsWonder.getCurrentRate();
            if (rate < 10) {
                oneSecondsWonder.setRate(oneSecondsWonder.getRate() + 1);
                System.out.println("Speed: " + oneSecondsWonder.getRate());
            }
        });        
        
        VBox root = new VBox(gridPane, new HBox(btnDecreaseSpeed, btnIncreaseSpeed));
        Scene scene = new Scene(root);
        stage.setTitle("Team 1");
        stage.setResizable(true); // Display the Resizable
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}

Edit Added Buttons to increase and decrease speed. Output not updated!

Output

enter image description here