Я выполнял университетский проект по построению решения дифференциального уравнения под названием модель Лотки-Вольтерри. Речь идет об отношениях между жертвами и хищниками в природе. Окно отображается нормально, когда я нажимаю любую из кнопок, программа выдает исключение в консоли. Я пытался самостоятельно разобраться, что не так, около 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>
Но тип оси - числа. private LineChart<Number, Number> figure;, на классах так и сделали, попробую поставить Double вставкой из Number.
Не в вашем FXML. Прочтите связанный мной вопрос и его решение.
Я, должно быть, пропустил это ... Большое спасибо.




Дубликат этого вопрос. Тем не менее, проблема может быть отправлена для Scene Builder здесь, чтобы разрешить изменение типа оси.