Java Scientific calculator GUI

Viewed 71

I am working on a calculator with a GUI. I'm not sure how I should gather all the numbers from the user and do the math for them. I tried storing them in variables, but that doesn't really work since I need to be able to have multiple numbers and operators at one time. Any input would be greatly appreciated. Thanks!

import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class GUI extends JFrame implements ActionListener {
    private JFrame frame;
    private JPanel buttons;

    //
    private JPanel text;
    private JTextField field;

    //
    private ImageIcon WCU;
    private JLabel labelWCU;

    ///
    JButton[] nums = new JButton[10];
    JButton[] functions = new JButton[15];

    ArrayList<Double> Addition = new ArrayList<>();

    double A;
    double S;
    double M;
    double D;
    double Answer;

    private JButton num1, num2, num3, num4, num5, num6, num7, num8, num9, num0;
    private JButton decimal, add, subtract, multiply, divide, equals, squareRoot;
    private JButton sin, cos, tan, exclamation, oneOverX, xSquared, log;
    private JButton clear;

    double input1 = 0, input2 = 0, answer = 0;
    char op;

    public GUI() {
        frame = new JFrame();
        buttons = new JPanel();

        //
        text = new JPanel();
        field = new JTextField(30);

        //
        WCU = new ImageIcon("WCU.png");
        labelWCU = new JLabel(WCU);
        

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("Calculator"); // make sure to center
        frame.setSize(525,750);
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setLayout(new BorderLayout());
        frame.add(text, BorderLayout.NORTH);
        frame.add(buttons, BorderLayout.CENTER);

        text.add(field);
        field.setEditable(false);
        text.setBackground(Color.RED);
        

        buttons.setBackground(Color.red);
        buttons.setBorder(BorderFactory.createEmptyBorder(20,50,300,50)); 
        buttons.setLayout(new GridLayout(6,4,20,20));

        //  
        buttons.add(decimal = new JButton ("."));
        functions[0] = decimal;

        buttons.add(add = new JButton ("+"));
        functions[1] = add;

        buttons.add(subtract = new JButton ("-"));
        functions[2] = subtract;

        buttons.add(multiply = new JButton ("*"));
        functions[3] = multiply;

        buttons.add(divide = new JButton ("/"));
        functions[4] = divide;

        buttons.add(equals = new JButton ("="));
        functions[5] = equals;

        buttons.add(squareRoot = new JButton ("√"));
        functions[6] = squareRoot;

        buttons.add(num1 = new JButton ("1"));
        nums[1] = num1;

        buttons.add(num2 = new JButton ("2"));
        nums[2] = num2;
        
        buttons.add(num3 = new JButton ("3"));
        nums[3] = num3;

        buttons.add(num4 = new JButton ("4"));
        nums[4] = num4;

        buttons.add(num5 = new JButton ("5"));
        nums[5] = num5;

        buttons.add(num6 = new JButton ("6"));
        nums[6] = num6;

        buttons.add(num7 = new JButton ("7"));
        nums[7] = num7;

        buttons.add(num8 = new JButton ("8"));
        nums[8] = num8;

        buttons.add(num9 = new JButton ("9"));
        nums[9] = num9;

        buttons.add(num0 = new JButton ("0"));
        nums[0] = num0;

        buttons.add(sin = new JButton ("sin"));
        functions[7] = sin;

        buttons.add(cos = new JButton ("cos"));
        functions[8] = cos;

        buttons.add(tan = new JButton ("tan"));
        functions[9] = tan;

        buttons.add(exclamation = new JButton ("!"));
        functions[10] = exclamation;

        buttons.add(oneOverX = new JButton ("1/x"));
        functions[11] = oneOverX;

        buttons.add(xSquared = new JButton ("x^2"));
        functions[12] = xSquared;

        buttons.add(log = new JButton ("log"));
        functions[13] = log;

        text.add(clear = new JButton("Clear"));
        functions[14] = clear;

        labelWCU.setIcon(WCU);

        frame.setVisible(true);

        //
        for (int i = 0; i < 15; i++){
            functions[i].addActionListener(this);
            functions[i].setFocusable(false);
        }

        for (int i = 0; i < 10; i++){
            nums[i].addActionListener(this);
            nums[i].setFocusable(false);
        }

    }
    
    public void actionPerformed(ActionEvent e){

        for (int i = 0; i < 10; i++){
            if(e.getSource() == nums[i]){
                field.setText(field.getText().concat(String.valueOf(i)));
            }
        }

        if(e.getSource() == decimal){
            field.setText(field.getText().concat("."));
        }

        if(e.getSource() == add){
            A = Double.parseDouble(field.getText());
            op = '+';
            field.setText("");
        }

        if(e.getSource() == subtract){
            input1 = Double.parseDouble(field.getText());
            op = '-';
            field.setText("");
        }

        if(e.getSource() == multiply){
            input1 = Double.parseDouble(field.getText());
            op = '*';
            field.setText("");
        }

        if(e.getSource() == divide){
            input1 = Double.parseDouble(field.getText());
            op = '/';
            field.setText("");
        }

        if(e.getSource() == equals){
            
            field.setText(String.valueOf(Addition));
        }

        if(e.getSource() == clear){
            field.setText("");
            A = 0;
        }

    }
}
1 Answers

I don't fully understand the purpose of all fields in your class, so I'll propose my own set. If we (ab)use the text field as storage for the current value, two state fields are enough for the basic functionality. It's not necessary to store any more data:

private String firstBinaryOperand = null;
private char binaryOp = ' ';

These fields are used if there is a pending binary operation such as + or -. We don't need them for unary operations. For example, if the user types "700 + 200 =", then

  • When the "+" button is pressed for the first time, the currently displayed value (700) is stored in firstBinaryOperand and '+' in binaryOp.
  • When the "=" button is pressed, the current value (200) and the value cached in firstBinaryOperand are added and the result (900) written into the text field.

We therefore need a method that evaluates a pending binary operation if there is one and writes the result into the text field:

// Evaluate pending binary operation, if there is one.
private void evaluateBinaryOp() {
    if (binaryOp != ' ') {
        double firstOperand = Double.parseDouble(firstBinaryOperand);
        double secondOperand = Double.parseDouble(field.getText());

        double result;
        if (binaryOp == '+') {
            field.setText(Double.toString(firstOperand + secondOperand));
        } else if (binaryOp == '-') {
            field.setText(Double.toString(firstOperand - secondOperand));
        }
        // Implementation of further binary operands ...

        // Update state, there is no longer a pending binary operation
        firstBinaryOperand = null;
        binaryOp = ' ';
    }
}

Addition as an example of a binary operation:

if (e.getSource() == add){
    evaluateBinaryOp(); // evaluate pending binary op, if any
    firstBinaryOperand = field.getText(); 
    binaryOp = '+'; 
    field.setText("0"); 
}

Unary operations are simpler, but we still have to check whether there is a pending binary operation and evaluate it first if this is the case:

if (e.getSource() == oneOverX) {
    evaluateBinaryOp(); // evaluate pending binary op, if any
    double currentValue = Double.parseDouble(field.getText()); 
    field.setText(Double.toString(1.0 / currentValue)); 
}

All other unary and binary operations can be implemented using the same pattern.

This is going to give you a very basic calculator whose behavior differs a bit from the usual. For example, if the user presses +, they will not see the intermediate result but always 0. The intermediate result isn't lost though as it is stored in the firrstBinaryOperand field in the background. The correct result will be shown once = or another unary operator is used. I hope this answers your question and is enough to get you started, you can then refine the behavior in a second step.

Related