4
\$\begingroup\$

This program is a basic pizza ordering program with seven topping options, four size options, and five crust options. It pulls the options from a database and populates the GUI on start.

I connected the images saved in the program to the strings associated with each topping. I used a recursive method to stack the topping images that will update each time a topping selection is made. The recursive method was the only solution I found that would restack the images without a blank space when a topping was deselected. It is working really well but I wanted to make it available for review.

The recursive method I used for the GUI is on the bottom of the code. There is also a lot of code written for the check box buttons. I'm not sure if I could have made that any shorter.

This is how the program looks:

enter image description here

public class FXMLDocumentController implements Initializable {

// variables with fx:id names for image views
@FXML
private ImageView ivOne;
@FXML
private ImageView ivTwo;
@FXML
private ImageView ivThree;
@FXML
private ImageView ivFour;
@FXML
private ImageView ivFive;
@FXML
private ImageView ivSix;
@FXML
private ImageView ivSeven;
@FXML
private ImageView ivSize;
@FXML
private ImageView ivCrust;

// create an image view array for the recursive method used to update the
// toppings images.
@FXML
private final ImageView[] iva = new ImageView[7];  

// array for toppings, size, and crust images
private Image[] topImgs = new Image[8];
private Image[] sizeImgs = new Image[4];
private Image[] crustImgs = new Image[5];

// variables for java text fields displaying price breakdown and total of pizza
@FXML
private TextField tfSizePrice;
@FXML
private TextField tfToppingsPrice;
@FXML
private TextField tfExtrasPrice;
@FXML
private TextField tfTotalPrice;
@FXML
private TextArea taPizzaOverview;

// variables for java radio button elements in display for pizza size
@FXML
private RadioButton radioButtonSizeOne;
@FXML
private RadioButton radioButtonSizeTwo;
@FXML
private RadioButton radioButtonSizeThree;
@FXML
private RadioButton radioButtonSizeFour;

// variables for java radio button elements in display for crusts
@FXML
private RadioButton rbCrustOne;
@FXML
private RadioButton rbCrustTwo;
@FXML
private RadioButton rbCrustThree;
@FXML
private RadioButton rbCrustFour;
@FXML
private RadioButton rbCrustFive;

// variables for java check box elements in display for toppings
@FXML
private CheckBox cbTopOne;
@FXML
private CheckBox cbTopTwo;
@FXML
private CheckBox cbTopThree;
@FXML
private CheckBox cbTopFour;
@FXML
private CheckBox cbTopFive;
@FXML
private CheckBox cbTopSix;
@FXML
private CheckBox cbTopSeven;

// radio button groups for size and crust. Only one may be selected
private final ToggleGroup sizeGroup = new ToggleGroup();
private final ToggleGroup crustGroup = new ToggleGroup();

// arrays that hold the database data
private String[] pizzaSize;
private String[] pizzaCrust;
private String[] pizzaToppings;

// strings of pizza choices to be displayed at the end.
private String sizeChoice = "Extra-Large";
private String crustChoice = "Deep Dish";
private String toppingsChoice = "";
private String pizzaOverview = "";

// variables for cost of toppings, size, crust, and total cost for the pizza
private double toppingsPrice = 0;
private double extrasPrice = 0;
private double sizePrice = 13;
private double totalPrice = 0;


/**
 * The action method for every button on the display that sorts the data
 * and returns the price and overview to the user.
 * @param event 
 */
@FXML
private void handleButtonAction(ActionEvent event) {

    Object source = event.getSource();

    // toppings buttons, adds 50 cents per topping or takes off 50 cents if user
    // changes their mind. These action events also add to the toppings string
    // or take off what the user deselected.
    if (source == cbTopOne){
        if (cbTopOne.isSelected() == true){
            toppingsChoice = toppingsChoice + pizzaToppings[0] + ". ";
            toppingsPrice = toppingsPrice + 0.5;
        }else{
            toppingsChoice = toppingsChoice.replace( pizzaToppings[0] + ". ", "");
            toppingsPrice = toppingsPrice - 0.5;
        }
    }else if (source == cbTopTwo){
        if (cbTopTwo.isSelected() == true){
            toppingsChoice = toppingsChoice + pizzaToppings[1] + ". ";
            toppingsPrice = toppingsPrice + 0.5;
        }else{
            toppingsChoice = toppingsChoice.replace( pizzaToppings[1] + ". ", "");
            toppingsPrice = toppingsPrice - 0.5;
        }
    }else if (source == cbTopThree){
        if (cbTopThree.isSelected() == true){
            toppingsChoice = toppingsChoice + pizzaToppings[2] + ". ";
            toppingsPrice = toppingsPrice + 0.5;
        }else{
            toppingsChoice = toppingsChoice.replace( pizzaToppings[2] + ". ", "");
            toppingsPrice = toppingsPrice - 0.5;
        }
    }else if (source == cbTopFour){
        if (cbTopFour.isSelected() == true){
            toppingsChoice = toppingsChoice + pizzaToppings[3] + ". ";
            toppingsPrice = toppingsPrice + 0.5;
        }else{
            toppingsChoice = toppingsChoice.replace( pizzaToppings[3] + ". ", "");
            toppingsPrice = toppingsPrice - 0.5;
        }
    }else if (source == cbTopFive){
       if (cbTopFive.isSelected() == true){
           toppingsChoice = toppingsChoice + pizzaToppings[4] + ". ";
            toppingsPrice = toppingsPrice + 0.5;
        }else{
           toppingsChoice = toppingsChoice.replace( pizzaToppings[4] + ". ", "");
           toppingsPrice = toppingsPrice - 0.5;
        }
    }else if (source == cbTopSix){
        if (cbTopSix.isSelected() == true){
            toppingsChoice = toppingsChoice + pizzaToppings[5] + ". ";
            toppingsPrice = toppingsPrice + 0.5;
        }else{
            toppingsChoice = toppingsChoice.replace( pizzaToppings[5] + ". ", "");
            toppingsPrice = toppingsPrice - 0.5;
        }
    }else if (source == cbTopSeven){
        if (cbTopSeven.isSelected() == true){
            toppingsChoice = toppingsChoice + pizzaToppings[6] + ". ";
            toppingsPrice = toppingsPrice + 0.5;
        }else{
            toppingsChoice = toppingsChoice.replace( pizzaToppings[6] + ". ", "");
            toppingsPrice = toppingsPrice - 0.5;
        }

    // raido buttons for pizza size, changes the base price of the pizza and the
    // text value of the size choice
    }else if (source == radioButtonSizeOne){
        sizeChoice = pizzaSize[0];
        ivSize.setImage(sizeImgs[0]);
        sizePrice = 13;
    }else if (source == radioButtonSizeTwo){
        sizeChoice = pizzaSize[1];
        ivSize.setImage(sizeImgs[1]);
        sizePrice = 11;
    }else if (source == radioButtonSizeThree){
        sizeChoice = pizzaSize[2];
        ivSize.setImage(sizeImgs[2]);
        sizePrice = 9;
    }else if (source == radioButtonSizeFour){
        sizeChoice = pizzaSize[3];
        ivSize.setImage(sizeImgs[3]);
        sizePrice = 7;

    // radio buttons for pizza crust, special crusts cost extra
    // and changes the text value of the crust choice variable
    }else if (source == rbCrustOne){
        crustChoice = pizzaCrust[0];
        ivCrust.setImage(crustImgs[0]);
        extrasPrice = 0;
    }else if (source == rbCrustTwo){
        crustChoice = pizzaCrust[1];
        ivCrust.setImage(crustImgs[1]);
        extrasPrice = 2;
    }else if (source == rbCrustThree){
        crustChoice = pizzaCrust[2];
        ivCrust.setImage(crustImgs[2]);
        extrasPrice = 0;
    }else if (source == rbCrustFour){
        crustChoice = pizzaCrust[3];
        ivCrust.setImage(crustImgs[3]);
        extrasPrice = 1;
    }else if (source == rbCrustFive){
        crustChoice = pizzaCrust[4];
        ivCrust.setImage(crustImgs[4]);
        extrasPrice = 0;
    }

    this.toppingImageOrder(toppingsChoice);

    // get total price and final overview
    totalPrice = toppingsPrice + sizePrice + extrasPrice;
    pizzaOverview = "Your Pizza: \n Size: " + sizeChoice + "\n Crust: " + crustChoice
            + "\n Your toppings choices are " + toppingsChoice;

    // display new costs seperated into parts so the user can see the breakdown
    // of the price.
    tfSizePrice.setText(Double.toString(sizePrice));
    tfToppingsPrice.setText(Double.toString(toppingsPrice));
    tfExtrasPrice.setText(Double.toString(extrasPrice));
    tfTotalPrice.setText(Double.toString(totalPrice));
    taPizzaOverview.setText(pizzaOverview);
} 

/**
 * Sets the display using data from the database to label the options
 * avaliable to the user.
 * @param url
 * @param rb 
 */
@Override
public void initialize(URL url, ResourceBundle rb) {
    // run method to connect to the database and collect 
    // the data into the arrays.
    try {
        this.getData();
    } catch (SQLException ex) {
        Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
    }

    // call the image class to collect the images and fill the image arrays
    Images im = new Images();
    im.Images();

    // call the array return methods from the image class to fill the arrays
    // in this class.
    topImgs = im.getTopImages();
    sizeImgs = im.getSizeImages();
    crustImgs = im.getCrustImages();

    // add the image values to the imageView array
    iva[0] = ivOne;
    iva[1] = ivTwo;
    iva[2] = ivThree;
    iva[3] = ivFour;
    iva[4] = ivFive;
    iva[5] = ivSix;
    iva[6] = ivSeven;

    // set the default size and crust choice images.
    ivCrust.setImage(crustImgs[0]);
    ivSize.setImage(sizeImgs[0]);

    // radio buttons for size added to group and labled by data from database
    radioButtonSizeOne.setToggleGroup(sizeGroup);
    radioButtonSizeOne.setText(pizzaSize[0]);

    radioButtonSizeTwo.setToggleGroup(sizeGroup);
    radioButtonSizeTwo.setText(pizzaSize[1]);

    radioButtonSizeThree.setToggleGroup(sizeGroup);
    radioButtonSizeThree.setText(pizzaSize[2]);

    radioButtonSizeFour.setToggleGroup(sizeGroup);
    radioButtonSizeFour.setText(pizzaSize[3]);

    radioButtonSizeOne.setSelected(true);

    // radio buttons for crust added to group and labled by data from database
    rbCrustOne.setToggleGroup(crustGroup);
    rbCrustOne.setText(pizzaCrust[0]);

    rbCrustTwo.setToggleGroup(crustGroup);
    rbCrustTwo.setText(pizzaCrust[1]);

    rbCrustThree.setToggleGroup(crustGroup);
    rbCrustThree.setText(pizzaCrust[2]);

    rbCrustFour.setToggleGroup(crustGroup);
    rbCrustFour.setText(pizzaCrust[3]);

    rbCrustFive.setToggleGroup(crustGroup);
    rbCrustFive.setText(pizzaCrust[4]);

    rbCrustOne.setSelected(true);

    // buttons for toppings labled by data from database
    cbTopOne.setText(pizzaToppings[0]);
    cbTopTwo.setText(pizzaToppings[1]);
    cbTopThree.setText(pizzaToppings[2]);
    cbTopFour.setText(pizzaToppings[3]);
    cbTopFive.setText(pizzaToppings[4]);
    cbTopSix.setText(pizzaToppings[5]);
    cbTopSeven.setText(pizzaToppings[6]);
}

/**
 * Calls database connector method and sorts data into arrays
 * @throws SQLException 
 */
public void getData() throws SQLException{


    // connect to the database
    PizzaDatabase pd = new PizzaDatabase();
    pd.connect();
    // connection variable
    Connection con = pd.getConnection();

    pd.createTables(con);

    // create an instance of each class used to collect db data and add it to
    // it's array.
    PizzaSize ps = new PizzaSize();
    ps.pizzaSize(con);
    PizzaCrust pc = new PizzaCrust();
    pc.pizzaCrust(con);
    PizzaToppings pt = new PizzaToppings();
    pt.pizzaToppings(con);

    // fill the arrays
    pizzaSize = ps.getSize();
    pizzaCrust = pc.getCrust();
    pizzaToppings = pt.getToppings();

    // close the connection
    con.close();
}

// a method to gain the amount of toppings and which are chosen
// that calls the recursive method that displays the corresponding images
// in order selected.
public void toppingImageOrder(String topChoiceString){
    // first clear the images in order to avoid leaving an image if the user
    // diselects a topping
    iva[0].setImage(null);
    iva[1].setImage(null);
    iva[2].setImage(null);
    iva[3].setImage(null);
    iva[4].setImage(null);
    iva[5].setImage(null);
    iva[6].setImage(null);

    try {
        // split the current topping choices into an array so that the program
        // can see how many toppings there are and will be able to determine how
        // many images it will update.
        String[] curTop = topChoiceString.split(" ");
        // gain the number of toppings
        int i = curTop.length;

        // pass the string to know which toppings and the integer to know
        // how many toppings
        imgLoop(i, curTop);

    }catch (PatternSyntaxException ex){

    }
}

/**
 * this is a recursive method that takes in how many images will be changed
 * and which toppings were chosen so it knows which images to display.
 * it uses the ImageView array in order to keep the toppings stacked close
 * to the pizza instead of just randomly placed on the GUI.
 * @param i
 * @param curTop 
 */
public void imgLoop(int i, String[] curTop){
    int img;

    if ( i > 0){
        i--;
        if(curTop[i].contains("sausage")){
            img = 0;
        }else if(curTop[i].contains("ham")){
            img = 1;
        }else if(curTop[i].contains("pepperoni")){
            img = 2;
        }else if(curTop[i].contains("green")){
            img = 3;
        }else if(curTop[i].contains("mushrooms")){
            img = 4;
        }else if(curTop[i].contains("olives")){
            img = 5;
        }else if(curTop[i].contains("chicken")){
            img = 6;
        }else{
            img = 7;
        }
        iva[i].setImage(topImgs[img]);
        imgLoop(i, curTop);
    }
}
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

There's a lot that can be said here, but I'll keep it to the main points of attention.

  • Yes, some of the data is loaded from the database, but it doesn't really make any difference; how many options there are per category is hard coded, and the toppings must match the hard coded images. The solution would be to add the options to the UI dynamically (this may be challenging).
  • One big class that does almost everything : manage presentation logic, get data from the DB, keep track of the pizza composition, pricing. You should take a look at MVC or MVP patterns.
  • The behavior of every single button is squeezed into one event handling method. Each buttons can have its own eventHandler, this will avoid the parade of if elses to determine which button it is. Similar event handlers can be instances of the same class with different parameters.
  • Empty catch block for PatternSyntaxException. It probably cannot occur, but if a bug is introduced and it does occur, you'll never find it. It's a RuntimeException, so just don't catch it. (I'm not saying RuntimeException should never be caught, I'm saying RuntimeExceptions that should never occur, shouldn't be caught)
\$\endgroup\$
1
  • \$\begingroup\$ Thank you, this is all fantastic advice!! I appreciate it! \$\endgroup\$ Commented Feb 10, 2017 at 15:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.