-2

I am writing a program that is a "sandwich ordering app". Think subway. Bread choice, meat choice, cheese choice, etc. I'm trying to use each type of element (radio buttons, combobox, slider, listview, checkbox, and textfield). I am having trouble with some of the listeners. I'm sure there's more than one way to do this, but I am getting nowhere. You'll see in my code that the commented out sections are the sections that are not working for me.

package sandwichorderapp;

import java.util.List;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.RadioButton;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.Slider;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**images go in bin folder in files
 *
 * @author toril
 */
public class SandwichOrderApp extends Application {
    
    public static int sandwichSize;
    public static String breadChoice;
    private final static String[] meats = {"Turkey", "Ham", "Steak", 
            "Chicken", "Bacon", "Pastrami"};
    private static String meatChoice;
    private static String cheeseChoice;
    //private static List<String> chosenToppings;
    private final static String[] sauces = {"Mayo", "Mustard", "Barbeque",
            "Ranch", "Buffalo"};
    //private static List<String> saucesChoice;
    //private static String saltPepperChoice;
    
    //method that returns a borderpane
    protected GridPane getPane(){

        //slider for sub size
        Slider sizeSlider = new Slider(6, 18, 12);
        sizeSlider.setShowTickLabels(true);
        sizeSlider.setShowTickMarks(true);
        sizeSlider.setBlockIncrement(6);
        //label the slider
        Label sliderLbl = new Label("Sandwich Size(in):", sizeSlider);
        sliderLbl.setContentDisplay(ContentDisplay.BOTTOM);
        sliderLbl.setUnderline(true);
        
        //listener for slider
        sizeSlider.valueProperty().addListener(e -> 
            sandwichSize = (int)sizeSlider.getValue());

        
        
        //create vbox for radio buttons and label
        VBox breadRadioButtons = new VBox();
        //text to label radio buttons:
        Text breadTxt = new Text("Bread Choice:");
        breadTxt.setUnderline(true);
                
        //set padding
        breadRadioButtons.setPadding(new Insets(5, 5, 5, 5));
        //create RadioButtons
        RadioButton whiteRB = new RadioButton("White");
        RadioButton wheatRB = new RadioButton("Wheat");
        RadioButton ryeRB = new RadioButton("Rye");
        RadioButton sourdRB = new RadioButton("Sourdough");
        //add RadioButtons to vbox
        breadRadioButtons.getChildren().addAll(breadTxt, whiteRB, wheatRB, ryeRB, sourdRB);
        breadRadioButtons.setAlignment(Pos.CENTER);
        
        //group the radio buttons
        final ToggleGroup breadGroup = new ToggleGroup();
        whiteRB.setToggleGroup(breadGroup);
        wheatRB.setToggleGroup(breadGroup);
        ryeRB.setToggleGroup(breadGroup);
        sourdRB.setToggleGroup(breadGroup);
        
        //set event handler for bread radiogroup
        whiteRB.setOnAction(e ->{
            if(whiteRB.isSelected()){
                breadChoice = "white";
            }
        });
        wheatRB.setOnAction(e -> {
            if(wheatRB.isSelected()){
                breadChoice = "wheat";
            }
        });
        ryeRB.setOnAction(e ->{
            if(ryeRB.isSelected()){
                breadChoice = "rye";
            }
        });
        sourdRB.setOnAction(e ->{
            if(sourdRB.isSelected()){
                breadChoice = "sourdough";
            }
        });
        
        
        
        //meat choices, more listview (can choose only one)
        //must call FXCollections because listview wants and arraylist, ot just an array
        ListView<String> meatsLV = new ListView<>(FXCollections.observableArrayList(meats));
        meatsLV.setPrefSize(80, 140);
        meatsLV.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
        Label meatsLbl = new Label("Meat Choice:", meatsLV);
        meatsLbl.setContentDisplay(ContentDisplay.BOTTOM);
        meatsLbl.setUnderline(true);
        
        //listener for meats list view
        meatsLV.getSelectionModel().selectedItemProperty().addListener(
                (ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
            meatChoice = newValue;
        });
        
        
        
        //choose cheese (only one, so I used comboBox)
        ComboBox<String> cheeseCB = new ComboBox<>();
        cheeseCB.getItems().addAll("Choose", "Cheddar", "Swiss", "Provolone", 
                "Pepper Jack", "American");
        cheeseCB.setValue("Choose");  //DEFAULT VALUE
        Label cheeseLbl = new Label("Cheese Choice:", cheeseCB);
        cheeseLbl.setContentDisplay(ContentDisplay.BOTTOM);
        cheeseLbl.setUnderline(true);

        //event handler for sandwich size combobox
        cheeseCB.getSelectionModel().selectedItemProperty().addListener((options, oldValue, newValue) ->{
            cheeseChoice = newValue;
        });
        
        
        
        //checkboxes for toppings
        VBox toppingsVB = new VBox();
        toppingsVB.setPadding(new Insets(5, 5, 5, 5));
        CheckBox chkLettuce = new CheckBox("Lettuce");
        CheckBox chkTomato = new CheckBox("Tomato");
        CheckBox chkCucumber = new CheckBox("Cucumber");
        toppingsVB.getChildren().addAll(chkLettuce, chkTomato,
                chkCucumber);
        Label toppingsLbl = new Label("Topping Choice:", toppingsVB);
        toppingsLbl.setContentDisplay(ContentDisplay.BOTTOM);
        toppingsLbl.setUnderline(true);
        
        //listeners for toppings
//        EventHandler toppingsHandler = new EventHandler<ActionEvent>() {
//            @Override
//            public void handle(ActionEvent event){
//                if(event.getSource() instanceof CheckBox) {
//                    CheckBox chb = (CheckBox) event.getSource();
//                    chosenToppings.add(chb.getText());
//                }
//            }
//        };
//        chkLettuce.setOnAction(toppingsHandler);
//        chkTomato.setOnAction(toppingsHandler);
//        chkCucumber.setOnAction(toppingsHandler);

        //Sauce choice
        ListView<String> saucesLV = new ListView<>(FXCollections.observableArrayList(sauces));
        saucesLV.setPrefSize(80, 117);
        saucesLV.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        Label saucesLbl = new Label("Sauce Choice:", saucesLV);
        saucesLbl.setContentDisplay(ContentDisplay.BOTTOM);
        saucesLbl.setUnderline(true);
        
        //listener for sauces list view
//        saucesLV.getSelectionModel().selectedItemProperty().addListener(
//                (ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
//            saucesChoice.
//        });
        
        //salt and pepper Y/N
        TextField tfSaltPepper = new TextField();
        Label saltPepperLbl = new Label("Salt and Pepper? (Y/N)", tfSaltPepper);
        saltPepperLbl.setContentDisplay(ContentDisplay.BOTTOM);
        saltPepperLbl.setUnderline(true);
        tfSaltPepper.setEditable(true);
        tfSaltPepper.setPrefWidth(30);
        
//        if("Y".equals(tfSaltPepper.getText()) || "y".equals(tfSaltPepper.getText())){
//        //listener for textfield
//            tfSaltPepper.setOnAction(e -> saltPepperChoice = "add salt and pepper");
//        }
//        else if("N".equals(tfSaltPepper.getText()) || "n".equals(tfSaltPepper.getText())){
//            tfSaltPepper.setOnAction(e -> saltPepperChoice = "no salt and pepper");
//        }
//        
        
        //textview to enter users choices after pressing button
        TextArea editTA = new TextArea();
        editTA.setVisible(false);
        editTA.setWrapText(true);
        
        
        //button to place order
        Button button = new Button("Order");
        
        button.setOnAction(e ->{
            editTA.setVisible(true);
            editTA.setText("Your Order:\nA " + sandwichSize + "in " + 
                    breadChoice + " bread sandwich with " + meatChoice + ", " +
                    cheeseChoice + " cheese, " + "<enter chosen toppings>," + 
                    " <enter chosen sauces>, " + "<enter salt/pepper choice>");
            
        
        });
    
        
        
        
        
        
        GridPane pane = new GridPane();
        //vbox to hold left of borderpane
        VBox leftVB = new VBox();
        //add both nodes to vbox and vbox to gridpane
        leftVB.getChildren().addAll(sliderLbl, breadRadioButtons, meatsLbl);
        VBox.setMargin(sliderLbl, new Insets(30,10,10,10));
        VBox.setMargin(breadRadioButtons, new Insets(10, 10, 10, 5));
        VBox.setMargin(breadTxt, new Insets(0, 0, 5, 0));
        VBox.setMargin(meatsLbl, new Insets(10, 10, 10, 35));
        
        //vbox for other nodes
        VBox rightVB = new VBox();
        //add nodes to vbox, then to gridpane
        rightVB.getChildren().addAll(cheeseLbl, toppingsLbl, saucesLbl, saltPepperLbl, button);
        VBox.setMargin(cheeseLbl, new Insets(30, 10, 10, 10));
        VBox.setMargin(toppingsLbl, new Insets(10, 10, 10, 20));
        VBox.setMargin(saucesLbl, new Insets(10, 10, 10, 20));
        VBox.setMargin(button, new Insets(20, 10, 10, 60));
        
        //HBox to hold nodes in an orderly way
        HBox hbox = new HBox();
        hbox.getChildren().addAll(leftVB, rightVB);
        
        pane.add(hbox, 0, 0);
        pane.add(editTA, 0, 1, 2, 2);
        
        return pane;
    }
    
    
    @Override
    public void start(Stage primaryStage) {
        //variables to hold users choices
        
        Scene scene = new Scene(getPane(), 300, 600);
        
        primaryStage.setTitle("Sandwich Order");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    
}

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
torireb
  • 1
  • 2
  • 1
    `I am having trouble with some of the listeners` : How silly the problem might be, try to explain the problem in the question – Sai Dandem May 05 '23 at 05:32
  • 2
    strip it down into isolated problems, solve each in isolation: write a [mcve] for each, modify until that single problem is solved (when stuck, present it here to get help) - only after having solved all, combine the parts :) – kleopatra May 05 '23 at 09:32
  • 3
    Off-topic: there is no reason for everything to be static here. – James_D May 05 '23 at 10:26
  • 1
    Maybe I am missing something, but I think this can be done without the listeners. I think you can get all the values needed after you click the order `Button` to construct your order string. – SedJ601 May 05 '23 at 15:00
  • 1
    @SedJ601 is correct: this can definitely be done without these listeners (or the variables). Is there a reason you need to keep track of all the user's choices the moment they change, instead of the usual approach of checking the values when the user commits all choices by pressing the button? – James_D May 05 '23 at 17:51
  • You all are entirely right on the point that I did not need the listeners. I'm really new to this, and I just learned listeners, so I'm seeing now that I just totally over-thought this one! Thanks for pointing that out - I was losing my mind. However, I got a lot of useful practice! (and thank you to @SaiDandem for helping me with the listeners!!) – torireb May 06 '23 at 04:27

1 Answers1

2

I think below are the main problems you are encountering with:

  • Choosing sauces from multi selection : You can add listener to the getSelectedItems() of selection model to build the list.

  • Getting the text for salt & pepper : You can add listener to the textProperty of the textfield to build the text

  • Building list for toppings : What you had is almost correct. You can add or remove the topping based on the checkbox selection.

Below is the updated code of your example. Please note that there can be many different ways to fix this. This is my attempt to fix this without going much into detail.

import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import java.util.*;

/**
 * images go in bin folder in files
 *
 * @author toril
 */
public class SandwichOrderApp extends Application {

    public static int sandwichSize;
    public static String breadChoice;
    private final static String[] meats = {"Turkey", "Ham", "Steak", "Chicken", "Bacon", "Pastrami"};
    private static String meatChoice = "no meat";
    private static String cheeseChoice = "no";
    private static Set<String> chosenToppings = new HashSet<>();
    private static List<String> chosenSauces = new ArrayList<>();
    private final static String[] sauces = {"Mayo", "Mustard", "Barbeque", "Ranch", "Buffalo"};

    private String saltPepperChoice = "no salt and pepper";

    //method that returns a borderpane
    protected GridPane getPane() {

        //slider for sub size
        Slider sizeSlider = new Slider(6, 18, 12);
        sizeSlider.setShowTickLabels(true);
        sizeSlider.setShowTickMarks(true);
        sizeSlider.setBlockIncrement(6);
        //label the slider
        Label sliderLbl = new Label("Sandwich Size(in):", sizeSlider);
        sliderLbl.setContentDisplay(ContentDisplay.BOTTOM);
        sliderLbl.setUnderline(true);

        //listener for slider
        sizeSlider.valueProperty().addListener(e -> sandwichSize = (int) sizeSlider.getValue());
        sandwichSize = (int) sizeSlider.getValue();

        //text to label radio buttons:
        Text breadTxt = new Text("Bread Choice:");
        breadTxt.setUnderline(true);

        //create RadioButtons
        RadioButton whiteRB = new RadioButton("White");
        whiteRB.setId("white");
        whiteRB.setSelected(true);
        RadioButton wheatRB = new RadioButton("Wheat");
        wheatRB.setId("wheat");
        RadioButton ryeRB = new RadioButton("Rye");
        ryeRB.setId("rye");
        RadioButton sourdRB = new RadioButton("Sourdough");
        sourdRB.setId("sourdough");

        VBox breadRadioButtons = new VBox();
        breadRadioButtons.setPadding(new Insets(5, 5, 5, 5));
        breadRadioButtons.getChildren().addAll(breadTxt, whiteRB, wheatRB, ryeRB, sourdRB);
        breadRadioButtons.setAlignment(Pos.CENTER_LEFT);

        //group the radio buttons
        final ToggleGroup breadGroup = new ToggleGroup();
        breadGroup.selectedToggleProperty().addListener((obs, old, val) -> breadChoice = ((Node) val).getId());
        whiteRB.setToggleGroup(breadGroup);
        wheatRB.setToggleGroup(breadGroup);
        ryeRB.setToggleGroup(breadGroup);
        sourdRB.setToggleGroup(breadGroup);

        //meat choices, more listview (can choose only one)
        //must call FXCollections because listview wants and arraylist, ot just an array
        ListView<String> meatsLV = new ListView<>(FXCollections.observableArrayList(meats));
        meatsLV.setPrefSize(80, 140);
        meatsLV.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
        Label meatsLbl = new Label("Meat Choice:", meatsLV);
        meatsLbl.setContentDisplay(ContentDisplay.BOTTOM);
        meatsLbl.setUnderline(true);

        //listener for meats list view
        meatsLV.getSelectionModel().selectedItemProperty().addListener(
                (ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
                    meatChoice = newValue != null ? newValue : "no meat";
                });


        //choose cheese (only one, so I used comboBox)
        ComboBox<String> cheeseCB = new ComboBox<>();
        cheeseCB.getItems().addAll("Choose", "Cheddar", "Swiss", "Provolone",
                "Pepper Jack", "American");
        cheeseCB.setValue("Choose");  //DEFAULT VALUE
        Label cheeseLbl = new Label("Cheese Choice:", cheeseCB);
        cheeseLbl.setContentDisplay(ContentDisplay.BOTTOM);
        cheeseLbl.setUnderline(true);

        //event handler for sandwich size combobox
        cheeseCB.getSelectionModel().selectedItemProperty().addListener((options, oldValue, newValue) -> cheeseChoice = newValue != null ? newValue : "no");


        //checkboxes for toppings
        VBox toppingsVB = new VBox();
        toppingsVB.setPadding(new Insets(5, 5, 5, 5));
        CheckBox chkLettuce = new CheckBox("Lettuce");
        CheckBox chkTomato = new CheckBox("Tomato");
        CheckBox chkCucumber = new CheckBox("Cucumber");
        toppingsVB.getChildren().addAll(chkLettuce, chkTomato, chkCucumber);
        Label toppingsLbl = new Label("Topping Choice:", toppingsVB);
        toppingsLbl.setContentDisplay(ContentDisplay.BOTTOM);
        toppingsLbl.setUnderline(true);

        //listeners for toppings
        EventHandler<ActionEvent> toppingsHandler = event -> {
            if (event.getSource() instanceof CheckBox) {
                CheckBox chb = (CheckBox) event.getSource();
                if (chb.isSelected()) {
                    chosenToppings.add(chb.getText());
                } else {
                    chosenToppings.remove(chb.getText());
                }
            }
        };
        chkLettuce.setOnAction(toppingsHandler);
        chkTomato.setOnAction(toppingsHandler);
        chkCucumber.setOnAction(toppingsHandler);

        //Sauce choice
        ListView<String> saucesLV = new ListView<>(FXCollections.observableArrayList(sauces));
        saucesLV.setPrefSize(80, 117);
        saucesLV.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        Label saucesLbl = new Label("Sauce Choice:", saucesLV);
        saucesLbl.setContentDisplay(ContentDisplay.BOTTOM);
        saucesLbl.setUnderline(true);

        //listener for sauces list view
        saucesLV.getSelectionModel().getSelectedItems().addListener((ListChangeListener<? super String>) p -> {
            chosenSauces.clear();
            chosenSauces.addAll(saucesLV.getSelectionModel().getSelectedItems());
        });

        //salt and pepper Y/N
        TextField tfSaltPepper = new TextField();
        tfSaltPepper.textProperty().addListener((obs, old, val) -> {
            if ("y".equalsIgnoreCase(val)) {
                saltPepperChoice = "add salt and pepper";
            } else {
                saltPepperChoice = "no salt and pepper";
            }
        });
        Label saltPepperLbl = new Label("Salt and Pepper? (Y/N)", tfSaltPepper);
        saltPepperLbl.setContentDisplay(ContentDisplay.BOTTOM);
        saltPepperLbl.setUnderline(true);
        tfSaltPepper.setEditable(true);
        tfSaltPepper.setPrefWidth(30);

        //textview to enter users choices after pressing button
        TextArea editTA = new TextArea();
        editTA.setVisible(false);
        editTA.setWrapText(true);


        //button to place order
        Button button = new Button("Order");

        button.setOnAction(e -> {
            editTA.setVisible(true);
            editTA.setText("Your Order:\nA " + sandwichSize + "in " +
                    breadChoice + " bread sandwich with " + meatChoice + ", " +
                    cheeseChoice + " cheese, " + buildString(chosenToppings) + " toppings, " + buildString(chosenSauces) +
                    " sauces, " + saltPepperChoice);
        });


        GridPane pane = new GridPane();
        //vbox to hold left of borderpane
        VBox leftVB = new VBox();
        //add both nodes to vbox and vbox to gridpane
        leftVB.getChildren().addAll(sliderLbl, breadRadioButtons, meatsLbl);
        VBox.setMargin(sliderLbl, new Insets(30, 10, 10, 10));
        VBox.setMargin(breadRadioButtons, new Insets(10, 10, 10, 5));
        VBox.setMargin(breadTxt, new Insets(0, 0, 5, 0));
        VBox.setMargin(meatsLbl, new Insets(10, 10, 10, 35));

        //vbox for other nodes
        VBox rightVB = new VBox();
        //add nodes to vbox, then to gridpane
        rightVB.getChildren().addAll(cheeseLbl, toppingsLbl, saucesLbl, saltPepperLbl, button);
        VBox.setMargin(cheeseLbl, new Insets(30, 10, 10, 10));
        VBox.setMargin(toppingsLbl, new Insets(10, 10, 10, 20));
        VBox.setMargin(saucesLbl, new Insets(10, 10, 10, 20));
        VBox.setMargin(button, new Insets(20, 10, 10, 60));

        //HBox to hold nodes in an orderly way
        HBox hbox = new HBox();
        hbox.getChildren().addAll(leftVB, rightVB);

        pane.add(hbox, 0, 0);
        pane.add(editTA, 0, 1, 2, 2);

        return pane;
    }

    private String buildString(Collection<String> collection) {
        String str = "";
        if (collection.isEmpty()) {
            str = "no ";
        } else {
            for (String top : collection) {
                str = str + top + ",";
            }
            str = str.substring(0, str.length() - 1) + " ";
        }
        return str;
    }

    @Override
    public void start(Stage primaryStage) {
        Scene scene = new Scene(getPane(), 300, 600);
        primaryStage.setTitle("Sandwich Order");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}
Sai Dandem
  • 8,229
  • 11
  • 26