На основе примера JewelSea на AnimatedAreaChart , я разрабатываю это решение для создания линейного графика в реальном времени, но я не знаю, как обновить набор данных (параллельная очередь)из другого потока.Может быть, решение может быть очень простым, но я замерз слишком много.
ПРОСТОЙ ГЛАВНЫЙ:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
public class Tester extends Application {
@Override
public void start(Stage primaryStage) {
try {
AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("Monitor.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
здесь базовый контроллер для fxml
package application;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
public class MonitorController implements Initializable {
@FXML
private AnchorPane arc_panel;
AnimatedLineChart sup=new AnimatedLineChart(6,250);
@Override
public void initialize(URL location, ResourceBundle resources) {
arc_panel.getChildren().add(sup.buildLineChart());
}
}
ЗДЕСЬАнимированная диаграмма
package application;
import javafx.animation.AnimationTimer;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class AnimatedLineChart {
private int MAX_DATA_POINTS = 150;
private int SENSNUM = 1;
private int xSeriesData = 0;
private ArrayList<XYChart.Series<Number, Number>> superiorSeries=new ArrayList<XYChart.Series<Number, Number>>();
private ArrayList<ConcurrentLinkedQueue<Number>> dataQs=new ArrayList<ConcurrentLinkedQueue<Number>>();
private ExecutorService executor;
private NumberAxis xAxis;
private AnimatedLineChart() {}//rendo costruttore di default privato
public AnimatedLineChart(int numOfChannels,int maxDataPointsPlotted) {
MAX_DATA_POINTS=maxDataPointsPlotted;
SENSNUM=numOfChannels;
}
public LineChart<Number, Number> buildLineChart() {
for (int i=0;i<SENSNUM;i++) {
XYChart.Series<Number, Number> seriesi = new XYChart.Series<>();
// Set Name for Series
seriesi.setName("SupCH"+i+1);
// Add Chart Series
superiorSeries.add(seriesi);
//PREPARE DATAQ HOLDER
dataQs.add(new ConcurrentLinkedQueue<Number>());
}
xAxis = new NumberAxis(0, MAX_DATA_POINTS, MAX_DATA_POINTS / 10);
xAxis.setForceZeroInRange(false);
xAxis.setAutoRanging(false);
xAxis.setTickLabelsVisible(false);
xAxis.setTickMarkVisible(false);
xAxis.setMinorTickVisible(false);
NumberAxis yAxis = new NumberAxis();
// Create a LineChart
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis) {
// Override to remove symbols on each data point
@Override
protected void dataItemAdded(Series<Number, Number> series, int itemIndex, Data<Number, Number> item) {
}
};
lineChart.setAnimated(false);
lineChart.setTitle("Superior Channels");
lineChart.setHorizontalGridLinesVisible(true);
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();
lineChart.getData().addAll(superiorSeries);
return lineChart;
}
//-- Timeline gets called in the JavaFX Tester 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<SENSNUM;i++) {
if (dataQs.get(i).isEmpty()) break;
superiorSeries.get(i).getData().add(new XYChart.Data<>(xSeriesData++, dataQs.get(i).remove()));
// remove points to keep us at no more than MAX_DATA_POINTS
if (superiorSeries.get(i).getData().size() > MAX_DATA_POINTS) {
superiorSeries.get(i).getData().remove(0, superiorSeries.get(i).getData().size() - MAX_DATA_POINTS);
}
}
// update
xAxis.setLowerBound(xSeriesData - MAX_DATA_POINTS);
xAxis.setUpperBound(xSeriesData - 1);
}
private class AddToQueue implements Runnable {
public void run() {
try {
// add a item of random data to queue
dataQs.get(0).add(Math.random()*2d);
dataQs.get(1).add(Math.random()*2d);
Thread.sleep(500);
executor.execute(this);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}