我的程序有问题。 我想在提供数据(等式的系数)之后绘制图表。
我试图更改我的导入(它有助于一些变量) 我将java.awt *更改为javafx.scene ...(少量导入)。
FXML文件:
<?xml version="1.0" encoding="UTF-8"?>
<?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.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="grahps.Controller">
<children>
<TextField fx:id="factorA" layoutX="24.0" layoutY="598.0" prefHeight="33.0" prefWidth="106.0" text="a=" AnchorPane.bottomAnchor="75.0" AnchorPane.leftAnchor="24.0" AnchorPane.rightAnchor="670.0" />
<TextField fx:id="factorB" layoutX="24.0" layoutY="630.0" prefHeight="33.0" prefWidth="106.0" text="b=" AnchorPane.bottomAnchor="37.0" AnchorPane.leftAnchor="24.0" AnchorPane.rightAnchor="670.0" />
<TextField fx:id="factorC" layoutX="24.0" layoutY="674.0" prefHeight="33.0" prefWidth="106.0" text="c=" AnchorPane.bottomAnchor="1.0" AnchorPane.leftAnchor="24.0" AnchorPane.rightAnchor="670.0" />
<TextField layoutX="158.0" layoutY="592.0" prefHeight="47.0" prefWidth="120.0" text="xMin=" AnchorPane.bottomAnchor="61.0" AnchorPane.leftAnchor="158.0" AnchorPane.rightAnchor="522.0" fx:id="xMin" />
<TextField layoutX="158.0" layoutY="650.0" prefHeight="47.0" prefWidth="120.0" text="xMax=" AnchorPane.bottomAnchor="3.0" AnchorPane.leftAnchor="158.0" AnchorPane.rightAnchor="522.0" fx:id="xMax" />
<Label fx:id="label" layoutX="468.0" layoutY="629.0" prefHeight="61.0" prefWidth="276.0" text="f(x)=" AnchorPane.bottomAnchor="30.0" AnchorPane.leftAnchor="468.0" AnchorPane.rightAnchor="56.0">
<font>
<Font size="18.0" />
</font>
</Label>
<LineChart fx:id="drawChart" prefHeight="598.0" prefWidth="800.0" title="Chart">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</LineChart>
<Button fx:id="button" layoutX="317.0" layoutY="612.0" mnemonicParsing="false" prefHeight="61.0" prefWidth="98.0" text="Rysuj wykres" />
</children>
</AnchorPane>
生成的带有LineChart(fx:id =“ drawChart”)的零件进行通信:“未解决的fx:id参考
我的主班:
package grahps;
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 {
private Controller controller;//
@Override
public void start(Stage stage) throws Exception {
stage.show();
System.out.println(getClass().getResource("/fxml/sample.fxml").getPath());
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/sample.fxml"));
loader.setController(controller);
Parent root = FXMLLoader.load(getClass().getResource("/fxml/sample.fxml"));
Scene scene = new Scene(root, 800, 800);
controller.drawChart(stage);
stage.setScene(scene);
}
public static void main(String[] args) {
launch(args);
}
}
最后是我的控制器:
package grahps;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.control.TextField;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
public class Controller {
@FXML
TextField factorA;
@FXML
TextField factorB;
@FXML
TextField factorC;
@FXML
TextField xMin;
@FXML
TextField xMax;
@FXML
Label label;
@FXML
Button button;
@FXML
XYChart.Series<Number, Number> chart;
//Parser Text Field -> double
double xMax1 = Double.parseDouble(xMax.getText());
double xMin1 = Double.parseDouble(xMin.getText());
double a = Double.parseDouble(factorA.getText());
double b = Double.parseDouble(factorB.getText());
double c = Double.parseDouble(factorC.getText());
@FXML
public void drawChart(Stage stage) {
XYChart.Series<Number, Number> series = chart;
series.setName("Chart");
final NumberAxis xAxis = new NumberAxis(xMin1, xMax1, 1);
final NumberAxis yAxis = new NumberAxis();
yAxis.setTickUnit(1);
xAxis.setLabel("X Label");
yAxis.setLabel("Y Label");
final javafx.scene.chart.LineChart<Number, Number> lineChart = new javafx.scene.chart.LineChart<Number, Number>(xAxis, yAxis);
double y;
String pattern;
if (a == 0 && c == 0) {
pattern = "f(x)=" + factorB;
label.setText(pattern);
} else if (c == 0) {
pattern = "f(x)=" + factorA + "x+" + factorB;
label.setText(pattern);
for (double i = xMin1; i <= xMax1; i++) {
y = a * i + b;
series.getData().add(new XYChart.Data(i, y));
}
} else {
pattern = "f(x)=" + factorC + "x^2" + factorA + "x+" + factorB;
label.setText(pattern);
for (double i = xMin1; i < xMax1; i++) {
y = a * i * i + b * i + c;
series.getData().add(new XYChart.Data(i, y));
}
}
lineChart.getData().add(series);
Scene scene = new Scene(lineChart, 800, 800);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
}
请注意一件事:这是我的第一个JavaFX项目。 我只是想填写方程式的系数,并在单击按钮后生成方程式+绘制图表。
我很乐意寻求帮助。
当我删除上述方法中的@FXML批注并编译代码时,出现了这些错误:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$154(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:748)
Caused by: javafx.fxml.LoadException:
/C:/Users/Damian/IdeaProjects/Graphs/target/classes/fxml/sample.fxml:14
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at grahps.Main.start(Main.java:22)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
... 1 more
Caused by: java.lang.NullPointerException
at grahps.Controller.<init>(Controller.java:31)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:927)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
... 17 more
Exception running application grahps.Main
Process finished with exit code 1
我也将onAction =“ drawChart”更改为onAction =“ chart”,现在可以看到突出显示的交流信息:“无法将javafx.scene.control.LineChart设置为图表”
答案 0 :(得分:1)
代码中有几个错误,例如:
控制器中的//Parser Text Field -> double
块执行得太早=> NullPointerException
。
在controller.drawChart(stage)
方法start
中调用controller
时等于null
=> NullPointerException
。
在控制器的drawChart
方法中,series
等于null
,因为chart
等于null
=> NullPointerException
。
控制器中缺少对图表的引用。评论中已经提到了这一点。
CategoryAxis
被用作x轴的类型,尽管x数据是数值。
在修复这些错误之前,应改进体系结构(这将自动修复某些错误):
Controller
级:由于必须先初始化图表,然后每次单击按钮才能更新图表,因此控制器中的以下更改将很有用:
实施一种initialize
方法,可以在其中进行必要的初始化。
实施一种updateChart
方法,该方法在单击按钮时会被调用,并会更新图表。
定义对LineChart的引用。
定义对两个轴的引用。
因此,Controller
类的外观如下:
public class Controller {
@FXML
TextField factorA;
@FXML
TextField factorB;
@FXML
TextField factorC;
@FXML
TextField xMin;
@FXML
TextField xMax;
@FXML
Label label;
@FXML
Button button;
@FXML
LineChart<Number, Number> chart;
@FXML
NumberAxis xAxis;
@FXML
NumberAxis yAxis;
@FXML
public void updateChart() {/*ToDo*/}
public void initialize(){/*ToDo*/}
}
Main
类:在start
方法中,仅需要加载FXML:
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/sample.fxml"));
Scene scene = new Scene(root, 800, 800);
stage.setScene(scene);
stage.show();
}
FXML:应该进行以下更改:
fx:id="chart"
NumberAxis
onAction="#updateChart"
添加到按钮。单击按钮时,将调用updateChart
方法。fx:id="xAxis"
和fx:id="yAxis"
)的ID。text="a="
)的初始化,否则解析存在问题(使用标签或水印,例如promptText="a"
更有意义)。 / li>
然后,FXML变为:
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="grahps.Controller">
<children>
<TextField fx:id="factorA" prefHeight="33.0" prefWidth="106.0" AnchorPane.bottomAnchor="75.0" AnchorPane.leftAnchor="24.0" AnchorPane.rightAnchor="670.0" promptText="a" />
<TextField fx:id="factorB" prefHeight="33.0" prefWidth="106.0" AnchorPane.bottomAnchor="37.0" AnchorPane.leftAnchor="24.0" AnchorPane.rightAnchor="670.0" promptText="b" />
<TextField fx:id="factorC" prefHeight="33.0" prefWidth="106.0" AnchorPane.bottomAnchor="1.0" AnchorPane.leftAnchor="24.0" AnchorPane.rightAnchor="670.0" promptText="c" />
<TextField fx:id="xMin" prefHeight="47.0" prefWidth="120.0" AnchorPane.bottomAnchor="61.0" AnchorPane.leftAnchor="158.0" AnchorPane.rightAnchor="522.0" promptText="xMin" />
<TextField fx:id="xMax" prefHeight="47.0" prefWidth="120.0" AnchorPane.bottomAnchor="3.0" AnchorPane.leftAnchor="158.0" AnchorPane.rightAnchor="522.0" promptText="xMax" />
<Label fx:id="label" prefHeight="61.0" prefWidth="276.0" AnchorPane.bottomAnchor="30.0" AnchorPane.leftAnchor="468.0" AnchorPane.rightAnchor="56.0" text="f(x)=" >
<font>
<Font size="18.0" />
</font>
</Label>
<LineChart fx:id="chart" prefHeight="598.0" prefWidth="800.0" title="Chart">
<xAxis>
<NumberAxis fx:id="xAxis" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yAxis" side="LEFT" />
</yAxis>
</LineChart>
<Button fx:id="button" prefHeight="61.0" prefWidth="98.0" layoutX="317.0" layoutY="612.0" mnemonicParsing="false" text="Rysuj wykres" onAction="#updateChart" />
</children>
</AnchorPane>
进行这些更改后,启动应用程序时将显示一个空图表(因为尚未实现初始化)。单击该按钮无效(因为尚未执行任何更新)。
初始化:
public void initialize(){
initChartProperties();
initInputControls();
XYChart.Series<Number, Number> series = getSeries();
chart.getData().add(series);
}
getSeries
方法本质上包含drawChart
方法的逻辑:
private XYChart.Series<Number, Number> getSeries() {
double xMax1 = Double.parseDouble(xMax.getText());
double xMin1 = Double.parseDouble(xMin.getText());
double a = Double.parseDouble(factorA.getText());
double b = Double.parseDouble(factorB.getText());
double c = Double.parseDouble(factorC.getText());
XYChart.Series<Number,Number> series = new XYChart.Series<Number, Number>();
series.setName("Chart");
String pattern;
if (a == 0 && c == 0) {
pattern = "f(x)=" + factorB.getText();
label.setText(pattern);
} else if (c == 0) {
pattern = "f(x)=" + factorA.getText() + "x+" + factorB.getText();
label.setText(pattern);
for (double i = xMin1; i <= xMax1; i++) {
double y = a * i + b;
series.getData().add(new Data<Number, Number>(i, y));
}
} else {
pattern = "f(x)=" + factorA.getText() + "x^2+" + factorB.getText() + "x+" + factorC.getText();
label.setText(pattern);
for (double i = xMin1; i < xMax1; i++) {
double y = a * i * i + b * i + c;
series.getData().add(new Data<Number, Number>(i, y));
}
}
return series;
}
initInputControls
方法初始化输入控件,例如:
private void initInputControls() {
xMax.setText("100.0");
xMin.setText("10.0");
factorA.setText("1.0");
factorB.setText("2.0");
factorC.setText("3.0");
}
initChartProperties
方法初始化图表:
private void initChartProperties() {
chart.setAnimated(true);
xAxis.setLabel("X Label");
yAxis.setLabel("Y Label");
}
如果要在启动时显示空白图表,只需删除initialize
方法中的最后三行。
更新:更新只是删除旧系列并将新系列添加到图表中:
@FXML
public void updateChart() {
XYChart.Series<Number, Number> series = getSeries();
chart.getData().clear();
chart.getData().add(series);
}
这些更改之后,应用程序将按预期运行。左图是启动后的应用程序,右图是更新输入值后的图。
有些事情仍然可以改进,例如如果更改窗口大小,应用程序将无法正确缩放。此外,缺少输入字段的验证。可以在initChartProperties
方法中禁用图表动画。
更新:
如果没有符号要显示,请添加initChartProperties
方法:
chart.setCreateSymbols(false);
结果是: