对于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复制功能吗?