4

This is a simple calculator where the user can type out the calculation and hit enter, and the calculator would determine if it is a valid calculation or not. If it is a valid calculation, the calculation is carried out. If not, an error message is written to the screen.

The calculation is carried out part isn't finished.

Can someone suggest a solutions to the getAnswer() method.

It would be very much appreciated.

import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;


@SuppressWarnings("serial")
public class Calculator extends JFrame{

    private interface CalculatorInterface {
        public void writeToScreen(String text);
        public void clearScreen();
        public String getScreenText();  
    }

    private class CalculatorPanel extends JPanel implements CalculatorInterface {

        private class NumberPanel extends JPanel implements CalculatorInterface {

            private static final int NUMTOTAL = 10;

            private CalculatorPanel calcPanel;
            private JButton[] numButtons;

            public NumberPanel(CalculatorPanel calcPanel) {
                this.calcPanel = calcPanel;
                buildLayout();
                addButtons();
            }
            private void buildLayout() {
                this.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

                GridLayout layout = new GridLayout(4,3);
                layout.setHgap(1);
                layout.setVgap(1);

                this.setLayout(new GridLayout(4,3));

            }
            private void addButtons() {
                numButtons = new JButton[NUMTOTAL];

                for(int i = numButtons.length -1; i >= 0 ; i--) {
                    numButtons[i] = new JButton("" + i);
                    numButtons[i].setPreferredSize(new Dimension(60,40));
                    numButtons[i].setFont(new Font("Sans serif", Font.PLAIN, 18));
                    numButtons[i].addActionListener(
                            new ActionListener() {
                                @Override
                                public void actionPerformed(ActionEvent e) {
                                    String text = ((JButton)e.getSource()).getText().trim();
                                    if(getScreenText().equals("Invalid Calc")) {
                                        clearScreen();
                                        writeToScreen(text);
                                    }else {
                                        writeToScreen(text);
                                    }       
                                }
                            });
                    this.add(numButtons[i]);
                }
            }
            @Override
            public void writeToScreen(String text) {
                calcPanel.writeToScreen(text);
            }
            @Override
            public void clearScreen() {
                calcPanel.clearScreen();

            }
            @Override
            public String getScreenText() {
                return calcPanel.getScreenText();
            }

        }

        private class OperPanel extends JPanel implements CalculatorInterface {

            private static final int ADD = 0;
            private static final int SUB = 1;
            private static final int MULT = 2;
            private static final int DIV = 3;
            private static final int OPENB = 4;
            private static final int CLOSEB = 5;
            private static final int CLEAR = 6;
            private static final int EQL = 7;


            private static final int OPERTOTAL = 8;

            private CalculatorPanel calcPanel;
            private JButton[] operButtons;

            public OperPanel(CalculatorPanel calcPanel) {
                this.calcPanel = calcPanel;
                buildLayout();
                addButtons();
            }

            private void buildLayout() {
                GridLayout layout = new GridLayout(4,1);
                layout.setHgap(1);
                layout.setVgap(1);

                this.setLayout(new GridLayout(4,1));
            }

            private void addButtons() {
                operButtons = new JButton[OPERTOTAL];

                operButtons[ADD] = makeButton(ADD, "+");
                operButtons[SUB] = makeButton(SUB, "-");
                operButtons[MULT] = makeButton(MULT, "*");
                operButtons[DIV] = makeButton(DIV, "/");
                operButtons[CLEAR] = makeButton(CLEAR, "CL");
                operButtons[EQL] = makeButton(EQL, "=");
                operButtons[OPENB] = makeButton(OPENB, "(");
                operButtons[CLOSEB] = makeButton(CLOSEB, ")");

                for(JButton button: operButtons) {
                    this.add(button);
                }   
            }

            private JButton makeButton(int index, String label) {   

                operButtons[index] = new JButton(label);
                operButtons[index].addActionListener(
                        new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                String text = ((JButton)e.getSource()).getText();
                                if(text.equals("=")) {
                                    String screenText = getScreenText();
                                    clearScreen();
                                    try {
                                        writeToScreen(getAnswer(screenText));
                                    }catch(Exception excep) {
                                        writeToScreen("Invalid Calc");
                                    }
                                }else if(text.equals("CL")) {
                                    clearScreen();  
                                }else {
                                    writeToScreen(text);
                                }
                            }       
                        });

                return operButtons[index];      
            }


            private String getAnswer(String text) throws Exception {
                /*I'm trying to solve for any input by the user e.g
                 *(the stuff in square brackets represents what is displayed
                 * on the screen:.
                 *[1+1] (hits equals) [2]
                 *[1+2-3] (hits equals) [0]
                 *[1+2*3] (hits equals) [7]
                 *[10*(14+1/2)] (hits equals) [145]
                 */
                throw new Exception();
            }
            @Override
            public String getScreenText() {
                return calcPanel.getScreenText();
            }

            @Override
            public void clearScreen() {
                calcPanel.clearScreen();

            }

            @Override
            public void writeToScreen(String text) {
                calcPanel.writeToScreen(text);

            }

        }


        private NumberPanel numPanel;

        private OperPanel operPanel;
        private JTextField calcScreen;

        public CalculatorPanel(JTextField calcScreen) {
            this.calcScreen = calcScreen;

            buildNumPanel();
            buildOperPanel();

            buildCalcPanel();


        }
        private void buildNumPanel() {
            this.numPanel = new NumberPanel(this);
        }

        private void buildOperPanel() {
            this.operPanel = new OperPanel(this);
        }

        private void buildCalcPanel() {
            this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
            this.add(numPanel);
            this.add(operPanel);
        }


        @Override
        public void writeToScreen(String text) {
            calcScreen.setText(getScreenText() + text);     
        }

        @Override
        public String getScreenText() {
            return calcScreen.getText();
        }

        @Override
        public void clearScreen() {
            calcScreen.setText("");
        }
    }

    private JPanel mainPanel;
    private JTextField calcScreen;

    private CalculatorPanel calcPanel;
    public Calculator() {
        buildScreen();

        buildCalcPanel();

        buildMainPanel();

        buildCalculator();
    }

    private void buildScreen() {
        this.calcScreen = new JTextField();
        this.calcScreen.setPreferredSize(new Dimension(150,50));
        this.calcScreen.setHorizontalAlignment(JTextField.CENTER);
        this.calcScreen.setFont(new Font("Sans serif", Font.PLAIN, 30));

    }

    private void buildCalcPanel() {
        this.calcPanel = new CalculatorPanel(this.calcScreen);
    }

    private void buildMainPanel() {
        this.mainPanel = new JPanel();
        this.mainPanel.setBorder(new EmptyBorder(10,10,10,10));
        this.mainPanel.setLayout(new BoxLayout(this.mainPanel, BoxLayout.Y_AXIS));

        this.mainPanel.add(calcScreen);
        this.mainPanel.add(calcPanel);
    }

    private void buildCalculator() {

        this.add(mainPanel);
        this.setTitle("Calculator");
        this.pack();        
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        @SuppressWarnings("unused")
        Calculator calc = new Calculator();
    }

}

How can I check to see if a string is a valid calculation for a simple calculator?

Edit 1: Fixed a silly bug in the makeButton() method were I passed in the text of the button to be verified instead of the text on screen. (I'm an idiot.)

Edit 2: Removed the isValid(String text) from the code and make it so the getAnswer() method just threw an exception if input is not a valid calculation.

2
  • 1
    Validation is going to be tricky, but I suggest you start out solving the easiest cases first: 1+1, 5+4+21, 5*1.2. Then move to more complex equations, refactoring your code as you go. My early solutions involved looking first for the operators, then their operands (the numbers). As I my understanding grew, I eventually developed calculators that turned string inputs into syntax trees, which I used for validation and calculation; but syntax trees are likely overkill for this problem. Commented Jul 12, 2015 at 5:05
  • 1
    For basic arithmetic operators, you can do this using a stack (and, if it's valid, calculate the result at the same time). Commented Jul 12, 2015 at 5:11

1 Answer 1

3

As well mentioned in a previous StackOverflow answer (Evaluating a math expression given in string form), you could use Javascript's ScriptEngine to calculate expressions based on strings that you would retrieve from the Text Field. Place it in a try-catch block first to see if there's an error in the expression. In the catch block, set the variable storing whether its a valid expression or not to false.

boolean validExpression = true;

ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String input = textField.getText() // Modify this to whatever variable you have assigned to your text field

try {
    System.out.println(engine.eval(foo));
} 
catch (ScriptException e) {
    validExpression = false;
    System.out.println("Invalid Expression");
}

Make sure you include the following imports:

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;

Although you could try to implement Shunting-Yard Algorithm or another arithmetic parser, this is simply a way more pragmatic solution.

Sign up to request clarification or add additional context in comments.

1 Comment

Although this is nice to know, it's a) overkill for the use-case and b) does nothing to help someone learn how to parse expressions.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.