如何在FXML控制器中实现更新的JavaFX LineChart?

时间:2018-10-09 16:37:38

标签: java javafx fxml linechart

对于JavaFX来说,我还很陌生,她想在可以执行实时更新的FXML Controller中实现折线图。我基于ItachiUchiha's example编写了代码,以提供以下控制器。当我取消注释AddDataToSeries中的代码以将数据添加到图形时,该代码似乎停止工作。

错误消息如下:

Exception in thread "JavaFX Application Thread" java.lang.ClassCastException:java.base/java.lang.Integer cannot be cast to java.base/java.lang.String
at javafx.controls/javafx.scene.chart.CategoryAxis.toNumericValue(Unknown Source)
at javafx.controls/javafx.scene.chart.LineChart.updateAxisRange(Unknown Source)
at javafx.controls/javafx.scene.chart.XYChart.layoutChartChildren(Unknown Source)

加上更多行的“未知来源”异常。

FXML控制器:

package application;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import javafx.animation.AnimationTimer;
import javafx.fxml.FXML;

import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.AnchorPane;

public class Graph1Controller {

private static final int MAX_DATA_POINTS = 20;
@FXML
private NumberAxis xAxis;
@FXML
private NumberAxis yAxis;

private int xSeriesData = 0;
private ExecutorService executor;

private XYChart.Series<Number, Number> series1 = new XYChart.Series<>();
private XYChart.Series<Number, Number> series2 = new XYChart.Series<>();
private XYChart.Series<Number, Number> series3 = new XYChart.Series<>();
private ConcurrentLinkedQueue<Number> dataQ1 = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<Number> dataQ2 = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<Number> dataQ3 = new ConcurrentLinkedQueue<>();

@FXML
private AnchorPane graphpane;
@FXML
private LineChart<Number,Number> linechart;


public Graph1Controller()
{

}

@FXML
private void initialize() {

    xAxis = new NumberAxis(0, MAX_DATA_POINTS, MAX_DATA_POINTS / 10);
    xAxis.setForceZeroInRange(false);
    xAxis.setAutoRanging(false);
    xAxis.setTickLabelsVisible(false);

    yAxis = new NumberAxis();
    yAxis.setForceZeroInRange(true);

    linechart.getData().addAll(series1, series2, series3); 

    series1.setName("Time1");
    series2.setName("Time2");
    series3.setName("Time3");

    executor = Executors.newCachedThreadPool(new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r);
            thread.setDaemon(true);
            return thread;
        }
    });

    AddToQueue addToQueue = new AddToQueue();
    executor.execute(addToQueue);
    //-- Prepare Timeline
    prepareTimeline();
}

private class AddToQueue implements Runnable {
    public void run() {
        try {
            // add a item of random data to queue
            dataQ1.add(Math.random());
            dataQ2.add(Math.random());
            dataQ3.add(Math.random());

            Thread.sleep(500);
            executor.execute(this);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

//-- Timeline gets called in the JavaFX Main thread
private void prepareTimeline() {
    // Every frame to take any data from queue and add to chart
    new AnimationTimer() {
        @Override
        public void handle(long now) {
            addDataToSeries();
        }
    }.start();
}

private void addDataToSeries() {
    for (int i = 0; i < 20; i++) { //-- add 20 numbers to the plot+
        if (dataQ1.isEmpty()) break;
        series1.getData().add(new XYChart.Data<>(xSeriesData++, dataQ1.remove()));
        series2.getData().add(new XYChart.Data<>(xSeriesData++, dataQ2.remove()));
        series3.getData().add(new XYChart.Data<>(xSeriesData++, dataQ3.remove()));
    }
    // remove points to keep us at no more than MAX_DATA_POINTS
    if (series1.getData().size() > MAX_DATA_POINTS) {
        series1.getData().remove(0, series1.getData().size() - MAX_DATA_POINTS);
    }
    if (series2.getData().size() > MAX_DATA_POINTS) {
        series2.getData().remove(0, series2.getData().size() - MAX_DATA_POINTS);
    }
    if (series3.getData().size() > MAX_DATA_POINTS) {
        series3.getData().remove(0, series3.getData().size() - MAX_DATA_POINTS);
    }
    // update
    xAxis.setLowerBound(xSeriesData - MAX_DATA_POINTS);
    xAxis.setUpperBound(xSeriesData - 1);
}

}

FXML代码:     

<?import javafx.scene.chart.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane fx:id="graphpane" prefHeight="500.0" prefWidth="500.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="application.Graph1Controller">
   <children>
      <LineChart fx:id="linechart" layoutX="7.0" layoutY="50.0" title="Recent Lap Times" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
        <xAxis>
          <CategoryAxis side="BOTTOM" />
        </xAxis>
        <yAxis>
          <NumberAxis side="LEFT" />
        </yAxis>
      </LineChart>
   </children>
</AnchorPane>

我已经搜索过,找不到直接答案或在FXML中实现更新折线图的示例,有人可以显示如何在上述示例中以FXML复制功能吗?

0 个答案:

没有答案