尝试从不同的控制器

时间:2017-06-28 21:39:59

标签: java javafx-8

在我的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。 我知道这是微不足道的,但我真的不知道该怎么做。

` 非常感谢您的帮助!

1 个答案:

答案 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方法提供给另一个。