在我的JavaFx应用程序中,我想在每次单击计算按钮时更新我的BarChart。问题是我得到了:
java.lang.NullPointerException at application.StatController.setActivityData(StatController.java:47)
总是指向:`xAxis.setCategories(optionsNames); 但它在列表中有元素(参见printscreen:https://image.ibb.co/b9YO8Q/Capture.png
在我的StatController类中,我有从FormController类调用的setActivityData。
StatController类:
public class StatController {
@FXML
private BarChart<String, Double> barChart;
@FXML
private CategoryAxis xAxis;
Activities activities = new Activities();
private Map<String, List<Double>> uniqueActivityOptions = new HashMap<>();
private ObservableList<String> optionsNames = FXCollections.observableArrayList();
public StatController(){}
@FXML
private void initialize() {
}
public void setActivityData(Activities activitiesList) {
for(Activity activity : activities.getActivityList()) {
String optionName = activity.getOption();
if(uniqueActivityOptions.containsKey(optionName)) {
uniqueActivityOptions.get(optionName).add((double) activity.getNumber());
} else {
List<Double> activityOptionList = new ArrayList<>();
activityOptionList.add((double) activity.getNumber());
uniqueActivityOptions.put(optionName, activityOptionList);
}
}
for (Map.Entry<String, List<Double>> entry : uniqueActivityOptions.entrySet()) {
optionsNames.add(entry.getKey());
}
xAxis.setCategories(optionsNames);
XYChart.Series<String, Double> series = new XYChart.Series<>();
for (Map.Entry<String, List<Double>> entry : uniqueActivityOptions.entrySet()) {
Double average = calculateAverage(entry.getValue());
series.getData().add(new XYChart.Data<>(entry.getKey().toString(), average));
}
barChart.getData().add(series);
}
private double calculateAverage(List<Double> values) {
double result = 0;
for (Double value : values) {
result += value;
}
return result / values.size();
}
}
FormController类:
public class FormController {
Activities act = new Activities();
List<Activity> activities = act.getActivityList();
private ObservableList<String> opt = FXCollections.observableArrayList(
"Option 1",
"Option 2",
"Option 3"
);
@FXML
private Button calculateButton;
@FXML
private TextField numberField;
@FXML
private ComboBox<String> options;
private String selectedOption;
@FXML
private void initialize() {
options.getItems().addAll(opt);
options.getSelectionModel().selectedItemProperty()
.addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
selectedOption = newValue;
}
});
}
@FXML
public void calculateButtonClicked(){
activities.add(new Activity(selectedOption, Integer.parseInt(numberField.getText())));
StatController sc = new StatController();
sc.setActivityData(act);
}
}
我在StatsController中测试了setActivityData方法,当我传递活动时它正常工作。
请告知代码中要更改的内容以传递和更新BarChart。 我知道这是微不足道的,但我真的不知道该怎么做。
` 非常感谢您的帮助!
答案 0 :(得分:0)
您的问题出在FormController#calculateButtonClicked()
。您手动创建StatController
的新实例,然后调用setActivityData()
方法。这不是JavaFX的工作原理,会导致xAxis
成员为空,因此您的NullPointerException
。
当您调用@FXML
方法时,FXMLLoader
类会注入带有FXMLLoader#load()
注释注释的控制器成员。您将需要使用FXMLLoader
类来加载与StatController
类对应的.fxml文件,然后该文件将为您创建StatController
对象的实例,并且还会注入您的 xAxis 和 barChart 实例。
这是一个快速(非生产就绪)示例,您必须根据具体情况进行调整:
FXMLLoader loader = new FXMLLoader();
loader.setLocation(filePath); // your path to the .fxml file
loader.load();
StatController controller = (StatController) loader.getController();
controller.setActivityData(activities); // your activities data
如何以及何时执行此操作取决于场景图的设置方式。查看源代码,我建议进行以下更改:
MainController.java
public class MainController
implements Initializable {
@FXML
private TabPane tabPane;
@FXML
private Tab formTabPage;
@FXML
private FormController formTabController; // change name to this
@FXML
private Tab statsTabPage;
@FXML
private StatController statsTabController; // change name to this
private MainApp mainApp;
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
@Override // rename your init() method to this
public void initialize(URL location, ResourceBundle resources) {
// add this line
formTabController.setStatController(statTabController);
}
}
FormController.java
public class FormController {
Activities act = new Activities();
List<Activity> activities = act.getActivityList();
private ObservableList<String> opt = FXCollections.observableArrayList(
"Option 1",
"Option 2",
"Option 3"
);
@FXML
private Button calculateButton;
@FXML
private TextField numberField;
@FXML
private ComboBox<String> options;
private String selectedOption;
private StatController statController; // add this member
@FXML
private void initialize() {
options.getItems().addAll(opt);
options.getSelectionModel().selectedItemProperty()
.addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
selectedOption = newValue;
}
});
}
@FXML
public void calculateButtonClicked() {
// change this method here
statController.setActivityData(act);
}
// add this method here
public void setStatController(StatController statController) {
this.statController = statController;
}
}
还有其他问题,但这会修复您的空指针异常。这个工作的原因和之前的代码没有,是因为您手动创建了StatController
的新实例,而没有使用FXMLLoader
已经加载并映射到用户界面节点的实例您。我上面所做的就是捕获对你需要的控制器的引用,并通过setter方法提供给另一个。