如何从FXML文件中指定图表的轴类型?似乎默认类型是<String, Integer>。如果将我的可注入字段声明为LineChart<Number, Number> lineChart,并使用创建数据系列(Number, Number,则程序将抛出ClassCastException。
<String, Integer>
LineChart<Number, Number> lineChart
(Number, Number
ClassCastException
必须使用FXML文件。最坏的情况是我手动创建图表。我最好的猜测是这是一个错误。
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进行了测试:
<?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>。
CategoryAxis
LineChart<Number, Number>
通常,您可以将两种数据类型(一种用于x,一种用于y)声明为所需的任何类型。自从你宣布
@FXML private LineChart<Number, Number> testChart ;
x变量的类型和y变量的类型均为Number。
Number
参照Javadocs的LineChart,a LineChart<X,Y>要求Axis<X>x轴和Axis<Y>y轴。因此Axis<Number>,每个轴都需要一个。A CategoryAxis是一个Axis<String>(再次,请参考Javadocs),因此它不能用作折线图的轴:该轴的数据类型与该图表的数据类型不兼容。
LineChart
LineChart<X,Y>
Axis<X>
Axis<Y>
Axis<Number>
Axis<String>
如果您在Java中尝试了以下操作:
LineChart<Number, Number> testChart ; testChart = new LineChart<>(new CategoryAxis(), new NumberAxis());
你会得到一个编译错误。由于(大概)要在FXML中初始化轴,并且FXML没有类型检查,因此可以ClassCastException在运行时获取。
可以帮助您的代码的一件事是使用正确键入的代码Series:
Series
private XYChart.Series<Number, Number> getDummyData() { final XYChart.Series<Number, Number> series = new XYChart.Series<>(); series.setName("My portfolio"); // ... }
现在,编译器将检查Series匹配类型是否与图表类型Data匹配,以及匹配类型是否与图表类型匹配Series。(因此series.getData().add(new XYChart.Data("1", 23));会产生编译错误,而不是运行时错误。)由于您是在FXML中创建轴的,因此仍然没有对这些轴进行类型检查,但我认为错误的原因(也许)会更加清楚。
Data
series.getData().add(new XYChart.Data("1", 23));
解决方法是使用NumberAxis,如上面的示例所示,而不是您的CategoryAxis。如果您确实想CategoryAxis在x轴上使用a ,则x值必须为Strings,因此您需要将LineChartas 声明为a LineChart<String, Number>。同样,您将制作Series一个Series<String, Number>。
NumberAxis
String
LineChart<String, Number>
Series<String, Number>