JavaFX LineChart - 由于Axis的类型而导致ClassCastException [英] JavaFX LineChart - ClassCastException because of the Axis' Type
问题描述
如何从FXML文件中指定图表的轴类型?看起来默认类型是< String,Integer>
。如果我将我的可注射字段声明为 LineChart< Number,Number> lineChart
,我用(Number,Number
)创建一个数据系列,程序抛出 ClassCastException
。
How do I specify the axis type for the chart from the FXML file? It seems like the default types are <String, Integer>
. If I declare my injectable field as LineChart<Number, Number> lineChart
, and the I create a data series with (Number, Number
), the program throws a ClassCastException
.
必须使用FXML文件。最糟糕的情况是我手动创建了我的图表。我最好的猜测是这是一个错误。
It is mandatory for a FXML File to be used. The worst case scenario would be that I created my chart manually. My best guess is that this is a bug.
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.AnchorPane;
/**
*
* @author ggrec
*
*/
public class TestChart implements Initializable
{
// ====================== 2. Instance Fields =============================
@FXML
private LineChart<Number, Number> testChart;
private AnchorPane anchorPane;
// ==================== 4. Constructors ====================
public TestChart()
{
final FXMLLoader fxmlLoader = new FXMLLoader( TestChart.class.getResource("testChart.fxml") );
fxmlLoader.setController(this);
try
{
anchorPane = (AnchorPane) fxmlLoader.load();
}
catch (final IOException e)
{
e.printStackTrace();
}
}
// ==================== 5. Creators ====================
@Override
public void initialize(final URL arg0, final ResourceBundle arg1)
{
// testChart.getXAxis().setAutoRanging(true);
// testChart.getYAxis().setAutoRanging(true);
testChart.getData().add(getDummyData());
}
// ==================== 7. Getters & Setters ====================
public AnchorPane getAnchorPane()
{
return anchorPane;
}
// ==================== 13. Utility Methods ====================
private XYChart.Series getDummyData()
{
final XYChart.Series series = new XYChart.Series();
series.setName("My portfolio");
series.getData().add(new XYChart.Data<Number, Number>(1, 23)); // Works for ("1", 23)
// series.getData().add(new XYChart.Data("2", 14));
// series.getData().add(new XYChart.Data("3", 15));
// series.getData().add(new XYChart.Data("4", 24));
// series.getData().add(new XYChart.Data("5", 34));
// series.getData().add(new XYChart.Data("6", 36));
// series.getData().add(new XYChart.Data("7", 22));
// series.getData().add(new XYChart.Data("8", 45));
// series.getData().add(new XYChart.Data("9", 43));
// series.getData().add(new XYChart.Data("10", 17));
// series.getData().add(new XYChart.Data("11", 29));
// series.getData().add(new XYChart.Data("12", 25));
return series;
}
}
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at javafx.scene.chart.CategoryAxis.invalidateRange(CategoryAxis.java:399)
at javafx.scene.chart.XYChart.updateAxisRange(XYChart.java:603)
at javafx.scene.chart.XYChart.layoutChartChildren(XYChart.java:620)
at javafx.scene.chart.Chart$1.layoutChildren(Chart.java:84)
at javafx.scene.Parent.layout(Parent.java:1018)
推荐答案
这对我来说很好。我使用以下FXML进行了测试:
This works fine for me. I tested with the following FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<AnchorPane xmlns:fx="http://javafx.com/fxml">
<LineChart fx:id="testChart">
<xAxis><NumberAxis /></xAxis>
<yAxis><NumberAxis /></yAxis>
</LineChart>
</AnchorPane>
和测试申请:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
TestChart chart = new TestChart();
Scene scene = new Scene(chart.getAnchorPane(), 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
有点难以说明为什么你会得到一个 ClassCastException
没有看到你的FXML文件(特别是你正在使用的轴)。但是,从堆栈跟踪中,您似乎使用的是 CategoryAxis
,它与 LineChart< Number,Number> 类型不兼容code>。
It's a little difficult to tell why you are getting a ClassCastException
without seeing your FXML file (and in particular the axes you are using). However, from the stack trace, it appears you are using a CategoryAxis
, which is not type-compatible with a LineChart<Number, Number>
.
通常,您可以将两种数据类型(一种用于x,一种用于y)声明为您想要的任何类型。由于您已宣布
In general, you can declare the two data types (one for x and one for y) to be any types you want. Since you've declared
@FXML
private LineChart<Number, Number> testChart ;
x变量的类型和y变量的类型都是数字
。
both the type of the x variable and the type of the y variable are Number
.
参考 Javadocs LineChart
, LineChart< X,Y>
x轴需要 Axis< X>
,y轴需要 Axis< Y>
。因此,每个轴需要 Axis< Number>
。 CategoryAxis
是 Axis< String>
(再次参考 Javadocs ),因此它不能用作折线图的轴:轴的数据类型与图表的数据类型不兼容。
Referring to the Javadocs for LineChart
, a LineChart<X,Y>
requires an Axis<X>
for the x-axis and an Axis<Y>
for the y-axis. So you need an Axis<Number>
for each axis. A CategoryAxis
is an Axis<String>
(again, refer to the Javadocs), so it cannot be used as an axis for your line chart: the data type for the axis is incompatible with the data type for the chart.
如果您在Java中尝试了以下内容:
If you tried the following in Java:
LineChart<Number, Number> testChart ;
testChart = new LineChart<>(new CategoryAxis(), new NumberAxis());
您将收到编译错误。由于您(可能)在FXML中初始化轴,并且FXML没有类型检查,因此您在运行时获得 ClassCastException
。
you would get a compile error. Since you're (presumably) initializing the axes in FXML, and FXML has no type checking, you get the ClassCastException
at runtime instead.
有助于您的代码的一件事是使用正确键入的系列
:
One thing that would help your code is to use a properly typed Series
:
private XYChart.Series<Number, Number> getDummyData()
{
final XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName("My portfolio");
// ...
}
现在编译器将检查 Series
的类型与图表的类型匹配, Data
的类型与<$的类型匹配C $ C>系列。 (所以 series.getData()。add(new XYChart.Data(1,23));
会产生编译错误,而不是运行时错误。)你在FXML中创建轴,你仍然没有类型检查,但我认为错误的原因(或许)会变得更清楚。
Now the compiler will check that the type of the Series
matches the type of the chart, and the type of the Data
matches the type of the Series
. (So series.getData().add(new XYChart.Data("1", 23));
would give a compile error, rather than a runtime error.) Since you are creating the axes in FXML, you still have no type checking on those but I think the cause of the error would (perhaps) become clearer.
修复是使用 NumberAxis
,如上例所示,而不是 CategoryAxis
。如果你真的想为x轴使用 CategoryAxis
,那么x值必须是 String
s,并且所以你需要将 LineChart
声明为 LineChart< String,Number>
。类似地,你可以使系列
a 系列<字符串,数字>
。
The fix is to use a NumberAxis
, as in my example above, instead of your CategoryAxis
. If you really want to use a CategoryAxis
for the x-axis, the x values have to be String
s, and so you need to declare the LineChart
as a LineChart<String, Number>
. Similarly you would make the Series
a Series<String, Number>
.
这篇关于JavaFX LineChart - 由于Axis的类型而导致ClassCastException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!