简体   繁体   中英

Change javafx circles color in certain time using multithreads

I am creating traffic light simulator with javafx that changes colour in every 2 seconds (first red light blinks and remain for 2 seconds) using the concept of multithreading. I have my code as given below. But it doesn't work as expected. It just blinks all light and sto Can somebody help me figure it out where I went wrong? Thanks

public void startThreads() throws InterruptedException {

    Runnable taskOne = new Runnable(){
        @Override
        public void run(){              
            try {
                Platform.runLater(new Runnable() {
                    @Override 
                    public void run() {
                        circle.setFill(Color.RED);
                        circle1.setFill(Color.GREY);
                        circle2.setFill(Color.GREY);
                    }
                  });
                Thread.currentThread().sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    Runnable taskTwo ......

    Runnable taskThree .....

    Thread thread1 = new Thread(taskOne);
    Thread thread2 = new Thread(taskTwo);
    Thread thread3 = new Thread(taskThree);

    //Start thread 1
    thread1.start();
    thread1.join();

    //start thread 2
    thread2.start();
    thread2.join();

    //Start thread 3
    thread3.start();
    thread3.join();
}

From the javadoc of Thread.join

Waits for this thread to die.

This means

thread1.start();
thread1.join();

doesn't provide any benefits compared to

taskOne.run();

since this stops the execution of the method invoking join until the Thread completes.


It's possible to achieve what you're trying to do in a much more elegant way by using Timeline :

Timeline timeline = new Timeline(
    new KeyFrame(Duration.ZERO, evt -> {
        circle.setFill(Color.RED);
        circle1.setFill(Color.GREY);
        circle2.setFill(Color.GREY);
    }),
    new KeyFrame(Duration.seconds(2), evt -> {
        // TODO: GUI modifications for second state
    }),
    new KeyFrame(Duration.seconds(4), evt -> {
        // TODO: GUI modifications for third state
    })
);
timeline.play();

You may need to adjust the duration for the third KeyFrame . The Duration parameter specifies the time from the beginning of the animation . The EventHandler<ActionEvent> s are executed on the JavaFX application thread and must not contain long-running code such as Thread.sleep . You may need to add additional KeyFrame s.

I was so confused on how to make this work honestly I agree with Sedrick check out the JavaFX Animation class but I was bored so I made this work also there is definitely better ways to do this but I did my best to try and keep as much code as possible because you wanted to lean from this. Just looked at this again its p̶r̶e̶t̶t̶y̶ ̶m̶u̶c̶h̶ only the variable names lol

public class Main extends Application {

    private Circle circle;
    private Circle circle1;
    private Circle circle2;
    private HashMap<Circle,Color> colorHashMap = new HashMap<>();
    private HashMap<Circle,Integer> counterHashMap = new HashMap<>();

    @Override
    public void start(Stage stage) {
        circle = new Circle(15, 15,30, Color.GREEN);
        colorHashMap.put(circle,Color.GREEN);
        counterHashMap.put(circle, 3);//Start On

        circle1 = new Circle(15, 45,30, Color.GREY);
        colorHashMap.put(circle1,Color.YELLOW);
        counterHashMap.put(circle1, 2);

        circle2 = new Circle(15, 60,30, Color.GREY);
        colorHashMap.put(circle2,Color.RED);
        counterHashMap.put(circle2, 1);

        VBox vBox = new VBox();
        vBox.getChildren().addAll(circle,circle1,circle2);

        Scene scene = new Scene(vBox);
        stage = new Stage();
        stage.setScene(scene);
        stage.show();

        try {
            startThreads();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void startThreads() throws InterruptedException {
        new Thread(()->{
            while (true) {
                flipColor(circle);
                flipColor(circle1);
                flipColor(circle2);

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void flipColor(Circle circle){
        if(counterHashMap.get(circle)%3==0) {
            Platform.runLater(()->circle.setFill(colorHashMap.get(circle)));
            counterHashMap.put(circle,1);
        }
        else {
            if(!circle.getFill().equals(Color.GREY))
                Platform.runLater(()->circle.setFill(Color.GREY));
            counterHashMap.put(circle,counterHashMap.get(circle)+1);
        }

    }

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

Here is an MCVE that uses Timeline . To get different durations use @fabian Timeline example. This example has a 2-second duration for all lights.

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 *
 * @author blj0011
 */
public class TrafficLightsFX extends Application
{

    String currentLight = "GREEN";

    @Override
    public void start(Stage primaryStage)
    {
        //Light GUI
        //https://www.color-hex.com/color-palette/35021
        String COLOR_GREEN_DARK = "#008000";
        String COLOR_GREEN = "47C746";
        String COLOR_YELLOW_DARK = "CA7602";
        String COLOR_YELLOW = "FFFF40";
        String COLOR_RED_DARK = "A30504";
        String COLOR_RED = "FF0000";

        Circle red = new Circle(25, Color.valueOf(COLOR_RED_DARK));
        Circle green = new Circle(25, Color.valueOf(COLOR_GREEN_DARK));
        Circle yellow = new Circle(25, Color.valueOf(COLOR_YELLOW_DARK));

        VBox trafficLight = new VBox(red, yellow, green);

        Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(2), (ActionEvent event) -> {
            switch (currentLight) {
                case "GREEN":
                    red.setFill(Color.valueOf(COLOR_RED_DARK));
                    green.setFill(Color.valueOf(COLOR_GREEN));
                    currentLight = "YELLOW";
                    break;
                case "RED":
                    yellow.setFill(Color.valueOf(COLOR_YELLOW_DARK));
                    red.setFill(Color.valueOf(COLOR_RED));
                    currentLight = "GREEN";
                    break;
                case "YELLOW":
                    green.setFill(Color.valueOf(COLOR_GREEN_DARK));
                    yellow.setFill(Color.valueOf(COLOR_YELLOW));
                    currentLight = "RED";
                    break;
            }
        }));
        timeline.setCycleCount(Timeline.INDEFINITE);

        Button btn = new Button();
        btn.setText("Start");
        btn.setOnAction((ActionEvent event) -> {
            switch (timeline.getStatus()) {
                case STOPPED:
                case PAUSED:
                    timeline.play();
                    break;
                case RUNNING:
                    timeline.pause();
                    break;
            }
        });

        VBox root = new VBox(new StackPane(trafficLight), btn);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM