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
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); }
}
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.
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);
}
}