JavaFX折线图不能很好地更新。数据问题

时间:2016-07-11 15:50:47

标签: javafx charts

我在更新LineChart数据时遇到了错误。更新LineChart x后,值无法更新。看起来函数的新值是“混合的”。实施Wave packet

对于两种情况,对于分散而没有它,应该看起来像是来自页面右侧的维基百科的当前动画。试图抓住这个问题出了什么问题,老实说,我看不出来。非常确定计数数据是100%好的。我在某处解决了这种问题,但无法解决我的问题。

主要课程:

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Animation 1D");
        primaryStage.setScene(new Scene(root, 1200, 800));
        primaryStage.show();
    }

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

轴类:

package sample;

import javafx.scene.chart.NumberAxis;

public class Axes {
    private NumberAxis xAxis;
    private NumberAxis yAxis;
    private double xMin, xMax, yMin, yMax, xTickUnit, yTickUnit;
    private int axesWidth, axesHeight;

    public Axes() {
        this.xMin = 0;
        this.xMax = 0;
        this.yMin = 0;
        this.yMax = 0;
        this.xTickUnit = 0;
        this.yTickUnit = 0;
        this.axesWidth = 0;
        this.axesHeight = 0;
    }

    public NumberAxis getXAxis() {
        return xAxis;
    }

    public NumberAxis getYAxis() {
        return yAxis;
    }

    public int getAxesWidth() {
        return axesWidth;
    }

    public void setAxesWidth(int axesWidth) {
        this.axesWidth = axesWidth;
    }

    public int getAxesHeight() {
        return axesHeight;
    }

    public void setAxesHeight(int axesHeight) {
        this.axesHeight = axesHeight;
    }

    public double getxMin() {
        return xMin;
    }

    public void setxMin(double xMin) {
        this.xMin = xMin;
    }

    public double getxMax() {
        return xMax;
    }

    public void setxMax(double xMax) {
        this.xMax = xMax;
    }

    public double getyMin() {
        return yMin;
    }

    public void setyMin(double yMin) {
        this.yMin = yMin;
    }

    public double getyMax() {
        return yMax;
    }

    public void setyMax(double yMax) {
        this.yMax = yMax;
    }

    public double getxTickUnit() {
        return xTickUnit;
    }

    public void setxTickUnit(double xTickUnit) {
        this.xTickUnit = xTickUnit;
    }

    public double getyTickUnit() {
        return yTickUnit;
    }

    public void setyTickUnit(double yTickUnit) {
        this.yTickUnit = yTickUnit;
    }

}

控制器类:

package sample;

import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.control.ComboBox;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import sample.packet3D.Window3DController;

import java.io.IOException;


public class Controller {

    @FXML
    private TextField xMin, xMax, yMin, yMax, xTick, yTick, width, height;
    @FXML
    private NumberAxis xAxis, yAxis;
    @FXML
    private ComboBox<String> comboBox;
    @FXML
    private LineChart<Double, Double> axesTest;
    @FXML
    private Label timeLabel;

    private GaussianWave gaussianWave;
    private GaussianWaveDispersive gaussianWaveDispersive;


    private Axes axes;

    private Series<Double, Double> series;

    private Timeline timeLine;
    @FXML
    public void initialize() 
    {
        System.out.println("Initialising...");
        axes = new Axes();

        yAxis.setAutoRanging(false);
        xAxis.setAutoRanging(false);

        xMin.setText("-30");
        xMax.setText("30");

        axesTest.setCreateSymbols(false);

        comboBox.getItems().addAll("Gaussian Wave : non-Dispersive", "Gaussian Wave : Dispersive");
        //comboBox.getItems().addAll("Gaussian Wave : non-Dispersive");
        series = new XYChart.Series<Double, Double>();

        timeLine = new Timeline();

        applyButtonClicked(null);
    }

    public void applyButtonClicked(ActionEvent event) 
    {
        System.out.println("Applying new parameters...");

        axes.setxMin(Double.parseDouble(xMin.getText()));
        axes.setxMax(Double.parseDouble(xMax.getText()));
        axes.setyMin(Double.parseDouble(yMin.getText()));
        axes.setyMax(Double.parseDouble(yMax.getText()));
        axes.setxTickUnit(Double.parseDouble(xTick.getText()));
        axes.setyTickUnit(Double.parseDouble(yTick.getText()));
        axes.setAxesWidth(Integer.parseInt(width.getText()));
        axes.setAxesHeight(Integer.parseInt(height.getText()));

        xAxis.setSide(Side.BOTTOM);
        xAxis.setMinorTickVisible(false);
        xAxis.setPrefWidth(axes.getAxesWidth());
        xAxis.setLayoutY(axes.getAxesHeight()/2);
        xAxis.autosize();

        xAxis.setLowerBound(axes.getxMin());
        xAxis.setUpperBound(axes.getxMax());
        xAxis.setTickUnit(axes.getxTickUnit());

        yAxis.setSide(Side.LEFT);
        yAxis.setMinorTickVisible(false);
        yAxis.setPrefHeight(axes.getAxesHeight());

        yAxis.setLowerBound(axes.getyMin());
        yAxis.setUpperBound(axes.getyMax());
        yAxis.setTickUnit(axes.getyTickUnit());


    }
    @FXML
    public void startButtonClicked(ActionEvent event) 
    {
        if (comboBox.getValue() == null) 
        {
            System.out.print("Nie wybrano opcji.");
        }
        else
        {
            if(comboBox.getValue().equals("Gaussian Wave : non-Dispersive")) 
            {
                System.out.println("Gaussian Wave : non-Dispersive");
                axesTest.setTitle("Gaussian Wave : non-Dispersive");

                if (series != null)
                {
                    series = new XYChart.Series<Double, Double>();
                }
                timeLine = new Timeline();
                gaussianWave = new GaussianWave( series, axes, timeLine );
                series = gaussianWave.draw();
                System.out.println("Rozmiar series: "+series.getData().size());
                gaussianWave.update(axesTest);


                axesTest.getData().add(series);
            }
            else if(comboBox.getValue().equals("Gaussian Wave : Dispersive")) 
            {
                System.out.println("Gaussian Wave : Dispersive");
                axesTest.setTitle("Gaussian Wave : Dispersive");

                if (series != null)
                {
                    series = new XYChart.Series<Double, Double>();
                }
                timeLine = new Timeline();
                gaussianWaveDispersive = new GaussianWaveDispersive( series, axes, timeLine );
                series = gaussianWaveDispersive.draw();
                System.out.println("Rozmiar series: "+series.getData().size());
                gaussianWaveDispersive.update(axesTest);

                axesTest.getData().add(series); 
    //            axesTest.setTitle("Gaussian Wave : Dispersive");
    //            gaussianWaveDispersive = new GaussianWaveDispersive(series, axes);
    //            series = gaussianWaveDispersive.draw();
    //
    //            gaussianWaveDispersive.update(axesTest);
    //
    //            axesTest.getData().add(series);
            }
        }
    }
    @FXML
    public void restartButtonClicked() {
        System.out.println("Restarting...");
        timeLine.getKeyFrames().clear();
        axesTest.getData().clear();
    }

    @FXML
    public void stopButtonClicked() {
        System.out.println("Stopping...");

        System.out.println("Restarting...");
        timeLine.getKeyFrames().clear();
        axesTest.getData().clear();  
        timeLine.stop();
    }

    @FXML
    public void moveTo3DScene(ActionEvent event) throws IOException {
        Stage stage3D = (Stage) ((Node) event.getSource()).getScene().getWindow();
        FXMLLoader loader = new FXMLLoader(getClass().getResource("packet3D/Window3DSceneView.fxml"));
        Parent root = loader.load();
        Window3DController controller = loader.getController();
        stage3D.setTitle("Animation 3D");
        Scene scene = new Scene(root, 1200, 800, false, SceneAntialiasing.BALANCED);
        scene.setOnKeyPressed(e -> controller.onKeyPressed(e));
        stage3D.setScene(scene);
        stage3D.show();
    }

    @FXML
    public void comboBoxAction() {

    }


}

接口类:

package sample;


import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;

public interface Countable {
    public abstract void methodCounting();
    @SuppressWarnings("rawtypes")
    public abstract XYChart.Series draw();
    public abstract void update(LineChart<Double, Double> lineChart);
}

通过Scene Builder生成的FXML类:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.chart.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<BorderPane fx:id="borderPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="650.0" prefWidth="1025.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
    <left>
        <VBox prefHeight="574.0" prefWidth="270.0" spacing="10.0" BorderPane.alignment="CENTER">
            <children>
                <GridPane hgap="10.0" vgap="10.0">
                    <columnConstraints>
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                        <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                    </columnConstraints>
                    <rowConstraints>
                        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                    </rowConstraints>
                    <children>
                        <TextField promptText="xMin" text="-1" GridPane.columnIndex="1" fx:id="xMin" />
                        <TextField promptText="xMax" text="1" GridPane.columnIndex="3" fx:id="xMax" />
                        <TextField fx:id="yMin" promptText="yMin" text="-1" GridPane.columnIndex="1" GridPane.rowIndex="1" />
                        <TextField fx:id="yMax" promptText="yMax" text="1" GridPane.columnIndex="3" GridPane.rowIndex="1" />
                        <TextField fx:id="width" promptText="width" text="1" GridPane.columnIndex="1" GridPane.rowIndex="3" />
                        <TextField fx:id="height" promptText="height" text="1" GridPane.columnIndex="3" GridPane.rowIndex="3" />
                        <TextField promptText="xTick" text="0.1" GridPane.columnIndex="1" GridPane.rowIndex="2" fx:id="xTick" />
                        <TextField fx:id="yTick" promptText="yTick" text="0.1" GridPane.columnIndex="3" GridPane.rowIndex="2" />
                  <Label text="xMin" />
                  <Label text="yMin" GridPane.rowIndex="1" />
                  <Label text="xTick" GridPane.rowIndex="2" />
                  <Label text="Width" GridPane.rowIndex="3" />
                  <Label text="Height" GridPane.columnIndex="2" GridPane.rowIndex="3" />
                  <Label text="yTick" GridPane.columnIndex="2" GridPane.rowIndex="2" />
                  <Label text="yMax" GridPane.columnIndex="2" GridPane.rowIndex="1" />
                  <Label text="xMax" GridPane.columnIndex="2" />
                    </children>
                    <padding>
                        <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
                    </padding>
                </GridPane>
                    <Button mnemonicParsing="false" onAction="#applyButtonClicked" prefHeight="25.0" prefWidth="200.0" text="Zatwierdź">
               <VBox.margin>
                  <Insets left="25.0" right="25.0" />
               </VBox.margin>
            </Button>
                <VBox>
                    <children>
                        <ComboBox fx:id="comboBox" onAction="#comboBoxAction" prefHeight="25.0" prefWidth="200.0">
                            <VBox.margin>
                                <Insets bottom="10.0" left="25.0" right="25.0" top="10.0" />
                            </VBox.margin>
                        </ComboBox>
                        <HBox spacing="10.0">
                            <children>
                                <Button fx:id="startButton" mnemonicParsing="false" onAction="#startButtonClicked" prefHeight="25.0" prefWidth="100.0" text="Rozpotrznij">
                                    <HBox.margin>
                                        <Insets />
                                    </HBox.margin>
                                </Button>
                                <Button fx:id="restartButton" mnemonicParsing="false" onAction="#restartButtonClicked" prefHeight="25.0" prefWidth="100.0" text="Zatrzymaj" />
                            </children>
                            <VBox.margin>
                                <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
                            </VBox.margin>
                            <padding>
                                <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
                            </padding>
                        </HBox>
                  <HBox>
                     <children>
                        <Button mnemonicParsing="false" onAction="#stopButtonClicked" prefHeight="25.0" prefWidth="200.0" text="Stop">
                           <HBox.margin>
                              <Insets left="25.0" right="25.0" />
                           </HBox.margin></Button>
                     </children>
                  </HBox>
                    </children>
                </VBox>
            <Button mnemonicParsing="false" onAction="#moveTo3DScene" prefHeight="25.0" prefWidth="200.0" text="Fala w przestrzeni 3D">
               <VBox.margin>
                  <Insets bottom="10.0" left="25.0" right="25.0" top="10.0" />
               </VBox.margin></Button>
            <HBox prefHeight="100.0" prefWidth="200.0" />
            </children>
            <BorderPane.margin>
                <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
            </BorderPane.margin>
            <padding>
                <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
            </padding>
        </VBox>
    </left>
    <center>
        <LineChart fx:id="axesTest" prefHeight="500.0" prefWidth="500.0" stylesheets="@style.css" BorderPane.alignment="CENTER">
            <xAxis>
                <NumberAxis lowerBound="-10.0" side="BOTTOM" fx:id="xAxis" />
            </xAxis>
            <yAxis>
                <NumberAxis fx:id="yAxis" lowerBound="-10.0" side="LEFT" />
            </yAxis>
        </LineChart>
    </center>
   <top>
      <ToolBar prefHeight="33.0" prefWidth="1025.0" BorderPane.alignment="CENTER">
        <items>
            <Label alignment="CENTER" text="JavaFX Simulation" textAlignment="CENTER">
               <opaqueInsets>
                  <Insets />
               </opaqueInsets>
            </Label>
            <Region prefHeight="29.0" prefWidth="738.0" />
            <Label fx:id="timeLabel" text="Time : " />
        </items>
      </ToolBar>
   </top>
</BorderPane>

计算波浪的2个逻辑类:

package sample;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.util.Duration;

import java.util.function.Function;


public class GaussianWave implements Countable{



    private Function<Double, Double> gaussFunction;
    private XYChart.Series<Double, Double> series;
    private Axes axes;
    private Timeline timeline;

    private double x;
    private double y;
    private double xInc;
    private double time;

    public GaussianWave(XYChart.Series<Double, Double> series, Axes axes, Timeline timeLine) {
        this.axes = axes;
        //this.series = new XYChart.Series<Number, Number>();
        this.series = series;
        this.timeline = timeLine;
        x = axes.getxMin();
        xInc = axes.getxTickUnit();
    }


    @Override
    public void methodCounting() {
        double lambda = 1;
            this.gaussFunction = x -> Math.sqrt(Math.pow(Math.exp(-(Math.pow((x - this.time), 2)))
                    * (Math.cos((2 * Math.PI * (x - this.time)) / lambda)), 2)
                    + Math.pow(Math.exp(-(Math.pow((x - this.time), 2)))
                    * (Math.sin((2 * Math.PI * (x - this.time)) / lambda)), 2));
    }

    @Override
    public Series<Double, Double> draw() {
        methodCounting();
        while(x < axes.getxMax()) {
            y = gaussFunction.apply(x);
            series.getData().add(new XYChart.Data<Double, Double>( x , y));
            x += xInc;
        }
        return series;
    }

    @Override
    public void update(LineChart<Double, Double> lineChart) {
        System.out.println("Updating");
        this.timeline.getKeyFrames().add(
                new KeyFrame(Duration.millis(100), e ->  {
                    for (XYChart.Series<Double, Double> series1 : lineChart.getData()) {
                        for (XYChart.Data<Double, Double> data : series1.getData()) {
                            Number y = gaussFunction.apply((double)data.getXValue());
                            data.setYValue((Double) y);
                            increaseTime();
                        }
                    }
                })
        );
        timeline.setCycleCount(1000);
        timeline.setAutoReverse(true);
        timeline.play();
    }


    public Function<Double, Double> getGaussFunction() {
        return gaussFunction;
    }

    public void setGaussFunction(Function<Double, Double> gaussFunction) {
        this.gaussFunction = gaussFunction;
    }

    public double getTime() {
        return time;
    }

    public void setTime(double time) {
        this.time = time;
    }

    public void increaseTime(){
        this.time += 0.001;
    }
    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }
}

package sample;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.util.Duration;

import java.util.function.Function;


public class GaussianWaveDispersive implements Countable{



    private Function<Double, Double> gaussFunction;
    private Series<Double, Double> series;
    private Axes axes;
    private Timeline timeline;

    private double x;
    private double y;
    private double xInc;
    private double time;


    public GaussianWaveDispersive(XYChart.Series<Double, Double> series, Axes axes, Timeline timeLine) {
        this.axes = axes;
        //this.series = new XYChart.Series<Number, Number>();
        this.series = series;
        this.timeline = timeLine;
        x = axes.getxMin();
        xInc = axes.getxTickUnit();
    }


    @Override
    public void methodCounting() {
        double lambda = 1;
        double k = (2 * Math.PI) / lambda;
            this.gaussFunction = x -> x =  Math.sqrt(Math.pow(1 / (Math.pow( ( 1 + Math.pow(4 * time, 2 )), (1/4)))
                    * Math.exp(-(( 1 / Math.pow(1 + (4 * time), 2)) * Math.pow(x - (k * time), 2) ))
                    * Math.cos((1/2) * Math.atan(-(2 * time)) + 1 / Math.pow(1 + (4 * time), 2)
                    * ((k + (2 * time * x)) * x - Math.pow(1/2 * time * k, 2))), 2)
                    + Math.pow(1 / (Math.pow( ( 1 + Math.pow(4 * time, 2 )), (1/4)))
                    * Math.exp(-(( 1 / Math.pow(1 + (4 * time), 2)) * Math.pow(x - (k * time), 2) ))
                    * Math.sin((1/2) * Math.atan(-(2 * time)) + 1 / Math.pow(1 + (4 * time), 2)
                    * ((k + (2 * time * x)) * x - Math.pow(1/2 * time * k, 2))), 2));
    }

    @Override
    public XYChart.Series<Double, Double> draw() {
        methodCounting();
        double count = 0;
        while(x < axes.getxMax()) {
            y = gaussFunction.apply(x);
            series.getData().add(new XYChart.Data<Double, Double>( x , y));
            x += xInc;
            count ++;
            System.out.println("Ilosc : " + count + "x : " +x);
        }
        return series;
    }

    @Override
    public void update(LineChart<Double, Double> lineChart) {
        System.out.println("Updating");
        this.timeline.getKeyFrames().add(
                new KeyFrame(Duration.millis(100), e ->  {
                    for (XYChart.Series<Double, Double> series1 : lineChart.getData()) {
                        for (XYChart.Data<Double, Double> data : series1.getData()) {
                            Number y = gaussFunction.apply((double)data.getXValue());
                            data.setYValue((Double) y);
                            increaseTime();
                        }
                    }
                })
        );
        timeline.setCycleCount(1000);
        timeline.setAutoReverse(true);
        timeline.play();
    }


    public Function<Double, Double> getGaussFunction() {
        return gaussFunction;
    }

    public void setGaussFunction(Function<Double, Double> gaussFunction) {
        this.gaussFunction = gaussFunction;
    }

    public double getTime() {
        return time;
    }

    public void setTime(double time) {
        this.time = time;
    }

    public void increaseTime(){
        this.time += 0.001;
    }
    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }
}

对于这种等级x的值非常高,我们可以观察到数据的混乱,应该像维基百科样本一样顺利,但事实并非如此。谁能告诉我哪里有问题?此外,使用较小的x / y刻度线和较大的xy轴时,它确实很滞后。原因是什么? 提前谢谢。

P.S。

SS显示了在更新线图之后它的外观。

1 个答案:

答案 0 :(得分:0)

解决此问题关闭线转到设置向下滚动到应用选择行停用移动数据打开线会出现一些信息,说明移动数据已关闭选择确定然后关闭线返回设置向下滚动到应用选择线然后打开移动数据然后关闭设置打开线及其完成