如何使BarChart像计时器一样工作?

时间:2018-11-10 20:10:41

标签: java multithreading javafx timer

我正在尝试使用JavaFX构建Quizz应用程序。 用户应该在一分钟内回答尽可能多的问题。我创建了BarChart的子类,我想用它来可视化剩余的时间。我的类实现了Runnable,因为计时器应该作为自己的线程运行(对吗?)。

我想将条形图设置为60,然后每秒减小一次条形。我尝试了不同的方法来执行此操作,但没有一个成功。

这是该类现在的样子:

public class StopWatchBar extends BarChart implements Runnable {

public StopWatchBar() {

super(new CategoryAxis(), new NumberAxis(0, 60, 1));

    super.setTitle("Time");
    this.setMaxWidth(200);
    this.setScaleShape(true);
    this.setAnimated(false);
    this.setCenterShape(true);
}

@Override
public void run() {

    XYChart.Series timeDataSeries = new XYChart.Series();
    timeDataSeries.getData().add(new XYChart.Data<String, Integer>("", 60));
    this.getData().add(timeDataSeries);

    int counterSeconds = 60;
    long startTime = System.currentTimeMillis();
    long endTime = System.currentTimeMillis() + (counterSeconds * 1000);
    long startTimePlusOneSecond = startTime + 1000;

    while (startTime < endTime) {
        if (startTime == startTimePlusOneSecond) {
            timeDataSeries.getData().clear();
            timeDataSeries.getData().add(new XYChart.Data<String, Number>("", counterSeconds));
            counterSeconds--;
            startTimePlusOneSecond += 1000;
        }
        startTime = System.currentTimeMillis();
    }
}

}

我已经在PrimaryStage中的Scene中创建了该类的对象作为实例对象。 在同一场景中,我还有一个按钮,我想使用它来测试执行计数器: 像这样:

timerTestButton.setOnAction(actionEvent -> {
        Thread timeBarRunner = new Thread(timeBar);
        timeBarRunner.start();
        });

当我按下UI中的按钮时,出现异常:

Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
at javafx.scene.chart.BarChart.seriesAdded(BarChart.java:293)
at javafx.scene.chart.XYChart.lambda$new$550(XYChart.java:160)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
at java.util.AbstractList.add(AbstractList.java:108)
at QuizGUI_classes.StopWatchBar.run(StopWatchBar.java:42)
at java.lang.Thread.run(Thread.java:748)

我不知道我是否在正确的道路上,希望有人对此有所了解。

1 个答案:

答案 0 :(得分:0)

以下是使用Timeline的示例。 Timeline设置为每秒运行一次。一旦计数器达到零,Timeline就会停止。

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class BarChartExperiments extends Application {

    Timeline timeline;
    int counter = 60;

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("BarChart Experiments");

        CategoryAxis xAxis    = new CategoryAxis();
        xAxis.setLabel("Devices");

        NumberAxis yAxis = new NumberAxis();
        yAxis.setLabel("Visits");

        BarChart     barChart = new BarChart(xAxis, yAxis);

        XYChart.Series dataSeries1 = new XYChart.Series();
        dataSeries1.setName("Time");

         barChart.getData().add(dataSeries1);
         barChart.setAnimated(false);
        dataSeries1.getData().add(new XYChart.Data("Time", counter));

        timeline = new Timeline(new KeyFrame(Duration.seconds(1), event ->{
            dataSeries1.getData().add(new XYChart.Data("Time", --counter));
            System.out.println(counter);
            if(counter == 0)
            {
                timeline.stop();
            }
        }));
        timeline.setCycleCount(Timeline.INDEFINITE);

        Button button = new Button("Start");
        button.setOnAction(event ->{
            switch(button.getText())
            {
                case "Start":
                    timeline.play();
                    button.setText("Reset");
                    break;
                case "Reset":
                    timeline.stop();
                    button.setText("Start");
                    counter = 60;
                    dataSeries1.getData().add(new XYChart.Data("Time", counter));
                    break;
            }
        });
        VBox vbox = new VBox(barChart, button);

        Scene scene = new Scene(vbox, 400, 200);

        primaryStage.setScene(scene);
        primaryStage.setHeight(600);
        primaryStage.setWidth(500);

        primaryStage.show();
    }

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

来自here

的更改代码