Печать в javafx приводит к тому, что ClassCastException Double не может преобразовать в строку - PullRequest
0 голосов
/ 21 ноября 2018

Я занимался разработкой университетского проекта для построения решения дифференциального уравнения, названного моделью Лотки-Вольтерри.Речь идет об отношениях между жертвами и хищниками в природе.Окно отображается нормально, когда я нажимаю любую из кнопок, программа выдает исключение в консоли.Я пытался выяснить самостоятельно, что идет не так в течение 2 часов безрезультатно.

Класс для создания данных работает по назначению, я создал csv-generator и построил его в Excel.

Вот мой класс контроллера:

package sample;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import org.apache.commons.math3.ode.FirstOrderDifferentialEquations;
import org.apache.commons.math3.ode.FirstOrderIntegrator;
import org.apache.commons.math3.ode.nonstiff.EulerIntegrator;

import java.util.ArrayList;

public class Controller {

    private double aHolder = -1;
    private double bHolder = -1;
    private double cHolder = -1;
    private double dHolder = -1;

    //datasets
    private XYChart.Series XT = new XYChart.Series();
    private XYChart.Series VT = new XYChart.Series();
    private XYChart.Series VX = new XYChart.Series();

    @FXML
    private TextField textA;

    @FXML
    private TextField textB;

    @FXML
    private TextField textC;

    @FXML
    private TextField textD;

    @FXML
    private Button plotXT;

    @FXML
    private Button plotVT;

    @FXML
    private Button plotVX;

    @FXML
    private LineChart<Number, Number> figure;

    @FXML
    private NumberAxis t;

    @FXML
    private NumberAxis x;

    @FXML
    void onclickPlotVT(ActionEvent event) {
        boolean isTheSame = checkIfTheSameAndSetIfNot();
        if(!isTheSame){
            calculate();
        }
        figure.getData().clear();
        figure.getData().add(VT);

    }

    @FXML
    void onclickPlotVX(ActionEvent event) {
        boolean isTheSame = checkIfTheSameAndSetIfNot();
        if(!isTheSame){
            calculate();
        }
        figure.getData().clear();
        figure.getData().add(VX);

    }

    @FXML
    void onclickPlotXT(ActionEvent event) {
        boolean isTheSame = checkIfTheSameAndSetIfNot();
        if(!isTheSame){
            calculate();
        }
        figure.getData().clear();
        figure.getData().add(XT);

    }

    //if
     private boolean checkIfTheSameAndSetIfNot(){
        double currentA = Double.parseDouble(textA.getText());
        double currentB = Double.parseDouble(textB.getText());
        double currentC = Double.parseDouble(textC.getText());
        double currentD = Double.parseDouble(textD.getText());

        boolean checkA = currentA == aHolder;
        boolean checkB = currentB == bHolder;
        boolean checkC = currentC == cHolder;
        boolean checkD = currentD == dHolder;

        //if all parameters are the same, return true, other way false
        if(checkA && checkB && checkC && checkD){
            return true;
        }

        aHolder = currentA;
        bHolder = currentB;
        cHolder = currentC;
        dHolder = currentD;

        return false;
    }

    private void calculate(){
        FirstOrderDifferentialEquations diffEquSolver = new DiffEquSolverZad2(aHolder, bHolder, cHolder, dHolder);
        FirstOrderIntegrator diffEquLIntegrator = new EulerIntegrator(0.01);
        DiffEquSolverPath diffSolverEquPath = new DiffEquSolverPath();
        double [] xStart = new double [] {0,0};
        double [] xStop = new double [] {10,10};
        diffEquLIntegrator.addStepHandler(diffSolverEquPath);
        diffEquLIntegrator.integrate(diffEquSolver,0,xStart,20,xStop);

        ArrayList<String> csv = diffSolverEquPath.getCsv();

        for(String s : csv){
            String data[] = s.split(",");
            XT.getData().add(new XYChart.Data(Double.parseDouble(data[0]), Double.parseDouble(data[1])));
            VT.getData().add(new XYChart.Data(Double.parseDouble(data[0]), Double.parseDouble(data[2])));
            VX.getData().add(new XYChart.Data(Double.parseDouble(data[1]), Double.parseDouble(data[2])));

        }

        System.out.println();
    }

}

Основной класс содержит только создание и ополаскивание сцены, созданной SceneBuilder.

Позиция стека после создания исключения выглядит следующим образом:

Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class java.lang.Double cannot be cast to class java.lang.String (java.lang.Double and java.lang.String are in module java.base of loader 'bootstrap')
    at javafx.controls/javafx.scene.chart.CategoryAxis.invalidateRange(CategoryAxis.java:456)
    at javafx.controls/javafx.scene.chart.LineChart.updateAxisRange(LineChart.java:207)
    at javafx.controls/javafx.scene.chart.XYChart.layoutChartChildren(XYChart.java:670)
    at javafx.controls/javafx.scene.chart.Chart$1.layoutChildren(Chart.java:95)
    at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1204)
    at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1211)
    at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1211)
    at javafx.graphics/javafx.scene.Scene.doLayoutPass(Scene.java:576)
    at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2482)
    at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:412)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:411)
    at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:438)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:519)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:499)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:492)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:320)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)

Другие классы (работают по назначению):

package sample;

import org.apache.commons.math3.exception.DimensionMismatchException;
import org.apache.commons.math3.exception.MaxCountExceededException;
import org.apache.commons.math3.ode.FirstOrderDifferentialEquations;

public class DiffEquSolverZad2 implements FirstOrderDifferentialEquations {
    private double a;
    private double b;
    private double c;
    private double d;


    public DiffEquSolverZad2(double a, double b, double c, double d) {
        if(a > 0 && b > 0 && c > 0 && d > 0) {
            this.a = a;
            this.b = b;
            this.c = c;
            this.d = d;
        } else {
            throw new IllegalArgumentException("All parameters must be greater than 0. ");
        }
    }



    @Override
    public int getDimension() {
        return 2;
    }

    @Override
    public void computeDerivatives(double t, double[] x, double[] dxdt) throws MaxCountExceededException, DimensionMismatchException {
        dxdt[0]= (a-b*x[1])*x[0];
        dxdt[1]= (c*x[0]-d)*x[1];
    }
}


package sample;

import org.apache.commons.math3.exception.MaxCountExceededException;
import org.apache.commons.math3.ode.sampling.StepHandler;
import org.apache.commons.math3.ode.sampling.StepInterpolator;

import java.util.ArrayList;
import java.util.Arrays;

public class DiffEquSolverPath implements StepHandler {

    private ArrayList<String> csv = new ArrayList<>();
    private ArrayList<Double> tValues = new ArrayList<>();

    public ArrayList<String> getCsv() {
        return csv;
    }

    public void clearCSVArray(){
        csv.clear();
    }

    @Override
    public void init(double v, double[] doubles, double v1) {

    }

    @Override
    public void handleStep(StepInterpolator stepInterpolator, boolean b) throws MaxCountExceededException {
        double t=stepInterpolator.getCurrentTime();//czas dla którego otrzymaliśmy rozwiązanie numeryczne(obliczono wartości xi v)
        double [] x=stepInterpolator.getInterpolatedState(); //wartości x i v

        csv.add(t+", "+ Arrays.toString(x).replace("[", "").replace("]", ""));

        tValues.add(t);
    }
}

    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("Zad5 from L5 Numeric Methods. ");
        primaryStage.setScene(new Scene(root, 1000, 600));
        primaryStage.show();
    }


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

Файл FXML:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="389.0" prefWidth="933.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <opaqueInsets>
      <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
   </opaqueInsets>
   <top>
      <VBox prefHeight="78.0" prefWidth="563.0" BorderPane.alignment="CENTER">
         <children>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="20.0">
               <children>
                  <Label prefHeight="50.0" prefWidth="119.0" text="Model Lotki-Volterry">
                     <font>
                        <Font name="System Bold" size="12.0" />
                     </font>
                  </Label>
                  <Label text="a:" />
                  <TextField fx:id="textA" promptText="1" />
                  <Label text="b:" />
                  <TextField fx:id="textB" promptText="1" />
                  <Label text="c:" />
                  <TextField fx:id="textC" promptText="1" />
                  <Label text="d:" />
                  <TextField fx:id="textD" promptText="1" />
               </children>
            </HBox>
            <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="30.0">
               <children>
                  <VBox alignment="CENTER" prefHeight="39.0" prefWidth="286.0">
                     <children>
                        <Label text="a – współczynnik przyrostu ofiar" />
                        <Label text="b – częstość umierania ofiar na skutek drapieżnictwa" />
                     </children>
                  </VBox>
                  <VBox alignment="CENTER" prefHeight="39.0" prefWidth="266.0">
                     <children>
                        <Label text="c – współczynnik przyrostu drapieżników" />
                        <Label text="d – częstość umierania drapieżników" />
                     </children>
                  </VBox>
                  <Button fx:id="plotXT" mnemonicParsing="false" onAction="#onclickPlotXT" text="Wykres x(t)" />
                  <Button fx:id="plotVT" mnemonicParsing="false" onAction="#onclickPlotVT" text="Wykres v(t)" />
                  <Button fx:id="plotVX" mnemonicParsing="false" onAction="#onclickPlotVX" text="Wykres v(x)" />
               </children>
            </HBox>
         </children>
      </VBox>
   </top>
   <center>
      <LineChart fx:id="figure" prefHeight="249.0" prefWidth="563.0" BorderPane.alignment="CENTER">
        <xAxis>
          <CategoryAxis side="BOTTOM" />
        </xAxis>
        <yAxis>
          <NumberAxis side="LEFT" />
        </yAxis>
      </LineChart>
   </center>
</BorderPane>
...