javajavafxcomboboxscenebuilderobservablelist

make two combo box related in javaFx


I Want to change the second comboBox items based on the user select of item in another comboBox. I do have courseCB comboBox that the user have to select first and then selct from mealCB comboBox; mealCB items should change based of courseCB select item.

   @FXML
    private ComboBox<String> courseCB;

    @FXML
    private ComboBox<String> mealCB;
  @FXML
    void initialize() {
     //   courseCB.
        ObservableList<String> courseList = FXCollections.observableArrayList(fileReader.getMealCourseArray());
        courseCB.setItems(courseList);
        courseCB.setValue("main meal");
        

 courseCB.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observableValue, String s, String t1) {
            switch (t1){
                case  "first meal": {
                    ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("first meal"));
                    mealCB.setItems(mealByCourse);
                }
                case "main meal": {
                    ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("main meal"));
                    mealCB.setItems(mealByCourse);
                }
                case "drink": {
                    ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("drink"));
                    mealCB.setItems(mealByCourse);
                }
                break;
            }
        }
    });
}

the code of getMealBycourse:

 public static String[] getMealsByCourse(String mealCourse){
        ArrayList<String> mealsList = new ArrayList<>();
        Meal[] meals ;
        fileReader filereader= new fileReader();
        meals = filereader.getMealArray();
        for (int i = 0; i < meals.length ; i++) {
            if ((meals[i].getMealCourse()).compareTo(mealCourse)==0) {
                mealsList.add(meals[i].getMealName());
            }
        }
        String [] mealsByCourse = mealsList.toArray(new String[mealsList.size()]);
        return mealsByCourse;
    }

fileReader.getMealCourseArray() will return an array of items of courseMeal and populate the courseCB (comboBox) with it. the problem is that that mealCB is getting values of drinks only. the method of get mealByCourse is working very well by testing it. so what is needed to change in the addListener to make it work.


Solution

  • This is related to these answers so also study them:

    You are using a similar approach to the first referenced answer, but have a logic error in your switch statement.

    You don't break after every condition, instead you break only at the end of the switch. So the other conditions are "working" as in doing what they are asked to do, but the subsequent conditions run too and only the last one applies.

    You can fix your logic error with the following code:

    switch (t1) {
        case "first meal": {
            ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("first meal"));
            mealCB.setItems(mealByCourse);
        }
        break; 
        case "main meal": {
            ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("main meal"));
            mealCB.setItems(mealByCourse);
        }
        break;
        case "drink": {
            ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("drink"));
            mealCB.setItems(mealByCourse);
        }
        break;
    }
    

    Note that I added break statements in between each case statement. That way, only the block of a single case statement will be executed for each case.

    I advise you to go back and do some study on the Java language basics. Study how switch statements work. That article is for Java 8. There are improved switches in later Java versions, but you aren't using the improved switch syntax, so the old article still applies for the old syntax that you use.

    If you want to switch to using a more modern syntax (requires Java 14+), then you can write instead:

    switch (t1) {
        case "first meal" -> {
            ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("first meal"));
            mealCB.setItems(mealByCourse);
        }
    
        case "main meal" -> {
            ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("main meal"));
            mealCB.setItems(mealByCourse);
        }
    
        case "drink" -> {
            ObservableList<String> mealByCourse = FXCollections.observableArrayList(fileReader.getMealsByCourse("drink"));
            mealCB.setItems(mealByCourse);
        }
    }
    

    This will do the same as the previous example, but is IMO, less error prone. It uses the new -> syntax for cases in switches rather than the old : syntax. The new syntax does not fall through cases and does not require explicit break statements.

    The switch can be converted to an expression to allow a more functional style of programming, which I often prefer:

    String[] mealsByCourse = switch (t1) {
        case "first meal" -> fileReader.getMealsByCourse("first meal");
        case "main meal" -> fileReader.getMealsByCourse("main meal");
        case "drink" -> fileReader.getMealsByCourse("drink");
        default -> new String[0];
    );
    
    mealCB.setItems(
        FXCollections.observableArrayList(
                mealsByCourse
        )
    );
    

    But then when you do that it becomes clear that you are just switching on a value and applying that value.

    So you can instead just eliminate the switch statement and use the simple solution proposed by Anon in comments:

    ObservableList<String> mealsByCourse = FXCollections.observableArrayList(
            fileReader.getMealsByCourse(t1)
    );                     
    
    mealCB.setItems(mealsByCourse);
    

    This final approach is the same as one of those proposed solutions in this answer to a related question: