Add values when JCheckBox clicked

后端 未结 3 1749
无人及你
无人及你 2020-12-22 02:04

My program contains a label with the caption “Choose a coffee” and four check boxes – Americano, Espresso, Double Espresso and Latte. Note: A JCheckBox array is recommended

相关标签:
3条回答
  • 2020-12-22 02:20

    First of all, you're not handling all the checkboxes the same way. For the first two choices, you add the price to the cost:

    cost += 3.75;
    

    whereas for the last two choices, you replace the cost:

    cost = 4.50;
    

    The first way is the correct way.

    Second, there's no reason to have the cost as a field. You should recompute the cost, and it should always start with 0, every time a checkbox selection changes. So cost should be a local variable of the actionPerformed() method.

    Third, there's no reason to change the label value before you know the final cost. So the lines

    String r = String.valueOf(cost);
    bMsg.setText(r);
    

    should only be there once, at the end of the actionPerformed() method, when the final cost is known.

    Finally, you want to use it us an array instead of handling each checkbos separately. It's quite easy, you just need to loop over the checkboxes:

    double prices = {3.75, 4.00, 4.50, 3.50};
    double cost = 0.0;
    for (int i = 0; i < boxes.length; i++) {
        if (boxes[i].isSelected()) {
            double price = prices[i];
            cost += price;
        }
    }
    // now display the cost in the label
    
    0 讨论(0)
  • 2020-12-22 02:28

    Your first problem (which you may or may not have noticed) is your array of JCheckBoxes only contains null elements:

    // check boxes are null here
    private JCheckBox americano, espresso, doubleEspresso, latte;
    
    // array created with only null elements
    JCheckBox[] boxes = new JCheckBox[]{americano, espresso, doubleEspresso, latte};
    

    So you need to create the array after instantiating the actual check boxes.

    ...
    
    americano = new JCheckBox("Americano", false);
    checkPanel.add(americano);
    americano.addActionListener(this);
    
    espresso = new JCheckBox("Espresso", false);
    checkPanel.add(espresso);
    espresso.addActionListener(this);
    
    doubleEspresso = new JCheckBox("Double Espresso", false);
    checkPanel.add(doubleEspresso);
    doubleEspresso.addActionListener(this);
    
    latte = new JCheckBox("Latte", false);
    checkPanel.add(latte);
    
    boxes = new JCheckBox[] {
        americano, espresso, doubleEspresso, latte
    };
    

    Then the assignment is suggesting to use arrays because you can create another parallel array of prices (which you did). But since you need these prices in parallel you cannot use a for each loop. You need the index. Then you need to recalculate the entire cost every time anything is selected or deselected.

    final double[] prices = {
        3.75, 4.00, 4.50, 3.50
    };
    
    ...
    
    double total = 0.0;
    
    for(int i = 0; i < boxes.length; i++) {
        if(boxes[i].isSelected()) {
            total += prices[i];
        }
    }
    

    There's two other notes that seem to be outside the scope of the assignment:

    • You should always make a class for this kind of association.
    • You should never use double for money. Use BigDecimal or something like it.

    Using a class makes logic simpler and not using double makes the calculation not incur error for this decimal addition.

    class PricePair {
        JCheckBox jCheckBox;
        BigDecimal price;
    }
    
    BigDecimal total = new BigDecimal("0.00");
    
    for(PricePair option : options) {
        if(option.jCheckBox.isSelected()) {
            total = total.add(option.price);
        }
    }
    
    0 讨论(0)
  • 2020-12-22 02:33

    Although both answers posted here are very helpful I'm adding this one because IMHO arrays are the less Object Oriented thing ever. You can achieve a more robust and OO solution following this hints:

    • Use putClientProperty() method inherited from JComponent to hold the prices in the check boxes.
    • Implement an ActionListener to add/substract the check box price to the total depending on the check box state. Use getClientProperty() method to retrieve the value stored in the check box.

    See the example below:

    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.math.BigDecimal;
    import java.math.BigInteger;
    import javax.swing.BoxLayout;
    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class Demo {
    
        BigDecimal total = new BigDecimal(BigInteger.ZERO);
    
        private void createAndShowGUI() {        
    
            final JLabel totalLabel = new JLabel("Total: ");
    
            ActionListener actionListener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JCheckBox checkBox = (JCheckBox)e.getSource();
                    BigDecimal value = (BigDecimal)checkBox.getClientProperty("price");
                    total = checkBox.isSelected() ? total.add(value) : total.subtract(value);
                    StringBuilder sb = new StringBuilder("Total: ").append(total);
                    totalLabel.setText(sb.toString());
                }
            };
    
            JCheckBox americano = new JCheckBox("Americano");
            americano.addActionListener(actionListener);
            americano.putClientProperty("price", new BigDecimal("3.75"));
    
            JCheckBox espresso = new JCheckBox("Espresso");
            espresso.addActionListener(actionListener);
            espresso.putClientProperty("price", new BigDecimal("4.00"));
    
            JCheckBox doubleEspresso = new JCheckBox("Double Espresso");
            doubleEspresso.addActionListener(actionListener);
            doubleEspresso.putClientProperty("price", new BigDecimal("4.50"));
    
            JCheckBox latte = new JCheckBox("Latte");
            latte.addActionListener(actionListener);
            latte.putClientProperty("price", new BigDecimal("3.50"));
    
            JPanel content = new JPanel();
            content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS));
            content.add(americano);
            content.add(espresso);
            content.add(doubleEspresso);
            content.add(latte);
            content.add(totalLabel);
    
            JFrame frame = new JFrame("Demo");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.add(content);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {                
                    new Demo().createAndShowGUI();
                }
            });
        }    
    }
    

    This way you can forget about mapping every check box with a value using arrays or maps. If you need to add a new sort of coffee you should simply add 4 lines like this:

    JCheckBox newCoffee = new JCheckBox("New Coffee");
    newCoffee.addActionListener(actionListener);
    newCoffee.putClientProperty("price", new BigDecimal("4.00"));
    
    content.add(newCoffee);
    
    0 讨论(0)
提交回复
热议问题