2017-06-28 3 views
1

JavaFxアプリケーションでは、計算ボタンをクリックするたびにBarChartを更新したいと考えています。問題は、私は取得していますということです。異なるコントローラからBarChartを設定しようとすると、javaFX nullpointer例外が発生する

application.StatController.setActivityData(StatController.java:47)でjava.lang.NullPointerExceptionが

それは常にを指している: `xAxis.setCategories( optionsNames); しかし、それは、リストの要素を持っている(PrintScreenを参照してください:私はFormControllerクラスから呼び出されたsetActivityDataを持っている私のStatControllerクラスでhttps://image.ibb.co/b9YO8Q/Capture.png

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

他のNPEの質問と全く同じです。 NPEをスローするコードでxAxis変数をどこで初期化しますか?実行可能な参照はどこに割り当てられますか? –

+0

nullpointerexceptionは何ですか、ObservableListの文字列はxAxis.setCategories(optionsNames)に渡されます。 xAxisは、JavaFXで使用される@FXMLによって初期化されます。 observableのリストがObservableListからxAxisに渡されることがわかります。 – erni

答えて

0

問題はFormController#calculateButtonClicked()です。 StatControllerの新しいインスタンスを手動で作成し、setActivityData()メソッドを呼び出します。これはJavaFXの仕組みではなく、xAxisメンバーがnullになるため、NullPointerExceptionになります。

@FXML注釈で注釈を付けられたコントローラのメンバーは、FXMLLoader#load()メソッドを呼び出すときにFXMLLoaderクラスによって注入されます。あなたは、あなたのためにあなたのStatControllerオブジェクトのインスタンスを作成し、またあなたのXAXIS棒グラフインスタンスを注入しますStatControllerクラスに対応.fxmlファイルをロードするためにFXMLLoaderクラスを使用する必要があります。

​​

いつ、どのようにあなたがそれを行う、あなたのシーングラフを設置している方法によって異なります。

は、ここでは、あなたの特定のシナリオに適応する必要があります(生産準備ができていません)簡単な例です。あなたのソースコードを見ると、私は次の変更を示唆している:

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; 
    } 
} 

が生じる他の問題があるが、これはあなたのNULLポインタを修正例外。この理由と以前のコードでは、StatControllerの新しいインスタンスを手動で作成し、FXMLLoaderが既にロードされ、ユーザーインターフェイスノードにマップされているインスタンスを使用していないためです。私が上で行ったことは、あなたが必要としているコントローラーへの参照をキャプチャし、セッターメソッドを通して他のコントローラーに提供することです。

+0

これは私のプロジェクトでどのように実装するのか分かりません。私のgitリポジトリ(https://github.com/ErniMJ/JavaFx/tree/master/src/application)をチェックして、何を変えるべきかのヒントを教えてくれますか? – erni

+0

@erniあなたのソースコードを見て、私の答えを更新しました。私が行った変更をコピーして貼り付けるのにいくつかの問題があったので、何かをかき乱すと、私に知らせてください。 – Cypher

+1

ちょうどテストされ、それは働いています!私が将来どのように使用できるかを教えてくれてありがとう! – erni

関連する問題