JavaFX通过FXML创建BarChart报错:无法实例化该组件
解决JavaFX FXML中BarChart实例化错误的方案
错误根源
- BarChart没有公共无参构造方法,FXML无法直接创建空实例,必须传入x轴和y轴参数。
- Controller中同时使用
@FXML注解和手动new BarChart<>(xAxis, yAxis),导致FXML注入与手动实例化冲突。
修复步骤
1. 修改FXML文件,定义坐标轴并关联BarChart
在FXML中添加坐标轴组件,通过属性绑定将其传入BarChart:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.geometry.Insets?> <?import javafx.scene.control.Label?> <?import javafx.scene.layout.VBox?> <?import javafx.event.ActionEvent?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.ComboBox?> <?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.GridPane?> <?import javafx.scene.control.TextField?> <?import javafx.collections.ListChangeListener.Change?> <?import javafx.scene.chart.BarChart?> <?import javafx.scene.chart.CategoryAxis?> <?import javafx.scene.chart.NumberAxis?> <GridPane hgap="15" vgap="15" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demo.HelloController"> <ComboBox fx:id="fromCurrency" onAction="#changeFromCurrencyCombo" GridPane.rowIndex="3" GridPane.columnIndex="2"/> <TextField fx:id="fromCurrencyText" onTextChange="#changeFromCurrencyText" GridPane.rowIndex="4" GridPane.columnIndex="2"/> <Label fx:id="fromCurrencyLabel" GridPane.rowIndex="5" GridPane.columnIndex="2"></Label> <Button fx:id="swapButton" text="↔" GridPane.rowIndex="6" GridPane.columnIndex="2" onAction="#swapButtonClicked"></Button> <ComboBox fx:id="toCurrency" onAction="#changeToCurrencyCombo" GridPane.rowIndex="7" GridPane.columnIndex="2"/> <Label fx:id="toCurrencyText" GridPane.rowIndex="8" GridPane.columnIndex="2"/><!--onTextChange="#changeToCurrencyText"--> <Label fx:id="toCurrencyLabel" GridPane.rowIndex="9" GridPane.columnIndex="2"></Label> <!-- 定义坐标轴 --> <CategoryAxis fx:id="xAxis" GridPane.rowIndex="10" GridPane.columnIndex="2"/> <NumberAxis fx:id="yAxis" GridPane.rowIndex="10" GridPane.columnIndex="2"/> <!-- 绑定坐标轴到BarChart --> <BarChart fx:id="chart" xAxis="$xAxis" yAxis="$yAxis" GridPane.rowIndex="10" GridPane.columnIndex="2"/> </GridPane>
2. 修改Controller代码,移除手动实例化逻辑
去掉手动创建的BarChart、xAxis、yAxis,仅保留FXML注入的变量:
package com.example.demo; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.chart.BarChart; import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.TextField; import java.net.URL; import java.util.List; import java.util.ResourceBundle; public class HelloController implements Initializable { @FXML public ComboBox fromCurrency; @FXML public ComboBox toCurrency; @FXML private Label fromCurrencyLabel; @FXML private Label toCurrencyLabel; @FXML private TextField fromCurrencyText; @FXML private Label toCurrencyText; public String currentFromCurrency = ""; //текущая валюта, из которой переводим public String currentToCurrency = ""; //текущая валюта, в которую переводим @FXML private ObservableList<String> items; @FXML private Button swapButton; @FXML private List<String> currencies; // 由FXML注入的坐标轴和图表 @FXML private CategoryAxis xAxis; @FXML private NumberAxis yAxis; @FXML private BarChart<String,Number> chart; private boolean canChange = true; @Override public void initialize(URL location, ResourceBundle resources) { items = FXCollections.observableArrayList("Рубль", "Доллар", "Евро", "Злотый"); fromCurrency.setItems(items); fromCurrency.setValue(items.get(0)); currentFromCurrency = items.get(0); toCurrency.setItems(items); toCurrency.setValue(items.get(1)); currentToCurrency = items.get(1); HelloParser par = new HelloParser(); par.connect(); currencies = par.getData(); par.checkDate(); drawChart(); } public void drawChart() { chart.setTitle("Country Summary"); xAxis.setLabel("Country"); yAxis.setLabel("Value"); XYChart.Series<String, Number> series1 = new XYChart.Series<>(); series1.setName("2003"); series1.getData().add(new XYChart.Data<>("Austria", 25601.34)); series1.getData().add(new XYChart.Data<>("Brazil", 20148.82)); series1.getData().add(new XYChart.Data<>("France", 10000)); series1.getData().add(new XYChart.Data<>("Italy", 35407.15)); series1.getData().add(new XYChart.Data<>("USA", 12000)); XYChart.Series<String, Number> series2 = new XYChart.Series<>(); series2.setName("2004"); series2.getData().add(new XYChart.Data<>("Austria", 57401.85)); series2.getData().add(new XYChart.Data<>("Brazil", 41941.19)); series2.getData().add(new XYChart.Data<>("France", 45263.37)); series2.getData().add(new XYChart.Data<>("Italy", 117320.16)); series2.getData().add(new XYChart.Data<>("USA", 14845.27)); XYChart.Series<String, Number> series3 = new XYChart.Series<>(); series3.setName("2005"); series3.getData().add(new XYChart.Data<>("Austria", 45000.65)); series3.getData().add(new XYChart.Data<>("Brazil", 44835.76)); series3.getData().add(new XYChart.Data<>("France", 18722.18)); series3.getData().add(new XYChart.Data<>("Italy", 17557.31)); series3.getData().add(new XYChart.Data<>("USA", 92633.68)); chart.getData().addAll(series1, series2, series3); } }
3. 额外优化说明
- 移除了非UI变量上错误的
@FXML注解(如currentFromCurrency、items)。 - 给
XYChart.Series添加泛型参数,消除未检查的编译警告。 - FXML中通过
$xAxis、$yAxis引用已定义的坐标轴实例,满足BarChart的构造参数要求。
内容的提问来源于stack exchange,提问作者Kerby3
相关产品推荐
相关产品推荐

