实时区域图表应用程序

时间:2015-04-07 06:00:50

标签: java netbeans javafx

我从stackoverflow中获取以下代码,当应用程序开始运行时,动态区域图表正在更新,几秒钟后应用程序挂起(即最小化,最大化,窗口关闭按钮在增加窗口大小后不起作用)。但面积图正在更新。

package areachartsample;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.AnimationTimer;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;


public class AreaChartSample extends Application {
    private static final int MAX_DATA_POINTS = 50;

    private Series series;
    private int xSeriesData = 0;
    private ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue<Number>();
    private ExecutorService executor;
    private AddToQueue addToQueue;
    private Timeline timeline2;
    private NumberAxis xAxis;

    private void init(Stage primaryStage) {
        xAxis = new NumberAxis(0,MAX_DATA_POINTS,MAX_DATA_POINTS/10);
        xAxis.setForceZeroInRange(false);
        xAxis.setAutoRanging(false);

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

        //-- Chart
        final AreaChart<Number, Number> sc = new AreaChart<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) {}
        };
        sc.setAnimated(false);
        sc.setId("liveAreaChart");
        sc.setTitle("Animated Area Chart");

        //-- Chart Series
        series = new AreaChart.Series<Number, Number>();
        series.setName("Area Chart Series");
        sc.getData().add(series);

        primaryStage.setScene(new Scene(sc));
    }

    @Override public void start(Stage primaryStage) throws Exception {
        init(primaryStage);
        primaryStage.show();

        //-- Prepare Executor Services
        executor = Executors.newCachedThreadPool(new ThreadFactory() {
            @Override public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setDaemon(true);
                return thread;
            }
        });
        addToQueue = new AddToQueue();
        executor.execute(addToQueue);
        //-- Prepare Timeline
        prepareTimeline();
    }

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

    private class AddToQueue implements Runnable {
        public void run() {
            try {
                // add a item of random data to queue
                dataQ.add(Math.random());
                Thread.sleep(50);
                executor.execute(this);
            } catch (InterruptedException ex) {
                Logger.getLogger(AreaChartSample.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    //-- 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 (dataQ.isEmpty()) break;
            series.getData().add(new AreaChart.Data(xSeriesData++, dataQ.remove()));
        }
        // remove points to keep us at no more than MAX_DATA_POINTS
        if (series.getData().size() > MAX_DATA_POINTS) {
            series.getData().remove(0, series.getData().size() - MAX_DATA_POINTS);
        }
        // update 
        xAxis.setLowerBound(xSeriesData-MAX_DATA_POINTS);
        xAxis.setUpperBound(xSeriesData-1);
    }
}

1 个答案:

答案 0 :(得分:0)

我为你创造了一个例子。它使用TimeLine进行图表更新。

import java.util.List;
import java.util.Random;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.stage.Stage;
import javafx.util.Duration;

public class LiveAreaChartApp extends Application {

    private static int MAX_DATA_POINTS = 10;
    private static int Y_DATA_RANGE = 100;
    private static int TICK_UNIT = 10;

    private static int UPDATE_INTERVAL_MS = 100;

    private AreaChart.Series<Number, Number> series1;
    private AreaChart.Series<Number, Number> series2;
    private AreaChart<Number, Number> areaChart;
    private NumberAxis xAxis = new NumberAxis();
    private NumberAxis yAxis = new NumberAxis();

    private SequentialTransition animation;

    private double nextX = 0;

    Random rnd = new Random();

    public LiveAreaChartApp() {

        Timeline timeline = new Timeline();
        timeline.getKeyFrames().add(new KeyFrame(Duration.millis( UPDATE_INTERVAL_MS), new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {

                // update chart data
                // note that we add one data point and remove one data point in this simple example. 
                // in a production environment you'd have to add multiple and remove multiple data points

                // add new points
                series1.getData().add(new XYChart.Data<Number, Number>(nextX, Math.sin(Math.toRadians(nextX)) * Y_DATA_RANGE));
                series2.getData().add(new XYChart.Data<Number, Number>(nextX, Math.cos(Math.toRadians(nextX)) * Y_DATA_RANGE));

                // remove points that shouldn't be visible anymore
                if (series1.getData().size() > MAX_DATA_POINTS) {
                    series1.getData().remove(0);
                }
                if (series2.getData().size() > MAX_DATA_POINTS) {
                    series2.getData().remove(0);
                }

                nextX += 10;

                // update using series 1 as reference
                // series 2 contains same amount of data; if it doesn't for your case,
                // you need to adapt this here and calculate the proper range
                List<Data<Number, Number>> data = series1.getData();
                xAxis.setLowerBound(data.get(0).getXValue().doubleValue());
                xAxis.setUpperBound(data.get(data.size() - 1).getXValue().doubleValue());

            }
        }));
        timeline.setCycleCount(Animation.INDEFINITE);

        animation = new SequentialTransition();
        animation.getChildren().addAll(timeline);
    }

    public Parent createContent() {
        xAxis = new NumberAxis();
        xAxis.setForceZeroInRange(false);
        xAxis.setAutoRanging(false);
        xAxis.setTickLabelsVisible(false);
        xAxis.setTickMarkVisible(false);
        xAxis.setMinorTickVisible(false);

        yAxis = new NumberAxis(-Y_DATA_RANGE, Y_DATA_RANGE, TICK_UNIT);
        yAxis.setAutoRanging(false);

        areaChart = new AreaChart<>(xAxis, yAxis);
        areaChart.setAnimated(false);
        areaChart.setLegendVisible(false);

        series1 = new AreaChart.Series<>();
        series1.getData().add(new AreaChart.Data<Number, Number>(0d, 0d));
        areaChart.getData().add(series1);

        series2 = new AreaChart.Series<>();
        series2.getData().add(new AreaChart.Data<Number, Number>(0d, 0d));
        areaChart.getData().add(series2);

        return areaChart;
    }

    public void play() {
        animation.play();
    }

    @Override
    public void stop() {
        animation.pause();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(new Scene(createContent()));
        primaryStage.show();
        play();
    }

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