使用多线程在特定时间内更改javafx圈子的颜色

时间:2018-10-01 10:57:40

标签: java multithreading javafx java-threads

我正在用javafx创建交通信号灯模拟器,它使用多线程的概念每2秒更改一次颜色(第一个红灯闪烁并保持2秒)。我有我的代码如下。但是它没有按预期工作。它只会闪烁所有指示灯,直到有人可以帮助我弄清楚我出了什么问题吗?谢谢

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

3 个答案:

答案 0 :(得分:3)

来自the javadoc of Thread.join

  

等待该线程死亡。

这是

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

相比,没有提供任何好处

taskOne.run();

因为这将停止执行调用join的方法,直到Thread完成为止。


通过使用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();

您可能需要调整第三个KeyFrame的持续时间。 Duration参数指定从动画开始开始的时间。 EventHandler<ActionEvent>在JavaFX应用程序线程上执行,并且不得包含长时间运行的代码,例如Thread.sleep。您可能需要添加其他KeyFrame

答案 1 :(得分:1)

我对如何诚实地进行这项工作感到非常困惑,我同意Sedrick签出JavaFX Animation类的经验,但是我很无聊,所以我完成了这项工作,当然也有更好的方法可以做到这一点,但是我尽了最大努力去保留尽可能多的代码,因为您想从中学习。只是再次看了看它的p̶r̶e̶t̶t̶y̶̶m̶u̶c̶h̶只有变量名大声笑

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

答案 2 :(得分:1)

这里是一个使用MCVETimeline。要获得不同的持续时间,请使用@fabian Timeline示例。此示例对所有灯的持续时间为2秒。

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

}