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