JavaFX LineChart - 由于Axis的类型而导致ClassCastException [英] JavaFX LineChart - ClassCastException because of the Axis' Type

查看:172
本文介绍了JavaFX LineChart - 由于Axis的类型而导致ClassCastException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从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>

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 Strings, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆