Back to Code List
java

Calculator

A basic calculator with some scientific and graphing capabilities.

   Calculator.java

import java.awt.Container;
import java.awt.Insets;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JToggleButton;

public class Calculator extends JFrame implements ActionListener,ItemListener {
	private JTextField displayText = new JTextField(30);
	private String[] keys = {"C","M","R","00",
							 "^","\u221A","%","/",
							 "7","8","9","*",
							 "4","5","6","-",
							 "1","2","3","+",
							 "0",".","+/-","="
							 };	
	private JButton[] button = new JButton[keys.length];
	private JToggleButton graphBtn;
	
	private String numStr1 = "0";
	private String numStr2 = "";
	private String memory = "";
	
	private char operation = ' ';
	private boolean firstInput = true;
	private boolean reset = false;
	private boolean isGraphing = false;
	
	public Calculator() {
		setTitle("My Calculator");
		setSize(235, (keys.length/4)*30+85);
		Container pane = getContentPane();
		
		pane.setLayout(null);
		displayText.setEditable(false);
		displayText.setHorizontalAlignment(JTextField.RIGHT);
		
		graphBtn = new JToggleButton("y=");
		graphBtn.addItemListener(this);
		graphBtn.setSize(50, 30);
		graphBtn.setLocation(10,5);
		graphBtn.setMargin(new Insets(2, 5, 2, 5));
		pane.add(graphBtn);
		
		displayText.setSize(150, 30);
		displayText.setLocation(60, 5);
		displayText.setText("0");
		pane.add(displayText);
		
		KeyEventDispatcher keyEventDispatcher = new KeyEventDispatcher() {
			@Override
			public boolean dispatchKeyEvent(KeyEvent e) {
			    if (e.getID() == KeyEvent.KEY_TYPED) {
			      char ch = e.getKeyChar();
			      doAction(ch);
			    }
			    return !isGraphing; // true to stop key event
			}
		};
		KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keyEventDispatcher);
		
		int x, y;
		
		x=10;
		y=40;
		for (int i=0; i<button.length; i++) {
			if (keys[i] != "") {
				button[i] = new JButton(keys[i]);
				button[i].addActionListener(this);
				button[i].setActionCommand(keys[i]);
				if (keys[i] == "\u221A") button[i].setActionCommand("@");
				if (keys[i] == "+/-") button[i].setActionCommand("s");
				if (keys[i] == "00") button[i].setActionCommand("z");
				button[i].setSize(50, 30);
				button[i].setLocation(x, y);
				button[i].setMargin(new Insets(2, 5, 2, 5));
				pane.add(button[i]);
			}
			x = x+50;
			if ((i+1)%4 == 0) {
				x = 10;
				y = y+30;
			}
		}
		
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		
		setVisible(true);
	}
	
	public void itemStateChanged(ItemEvent e) {
        if(e.getStateChange() == ItemEvent.SELECTED)
        {
			showGraphing();
        }
        else
        {
			hideGraphing();
        } 
    }
	
	public void showGraphing() {
		isGraphing = true;
		displayText.setText("");
		//show buttons
		button[1].setText("(");
		button[2].setText(")");
		button[3].setText("X");
		button[4].setText("pow");
		button[5].setText("sqrt");
		button[22].setText(",");
		button[23].setText("Go");
	}
	
	public void hideGraphing() {
		//reset everything
		numStr1 = "0";
		numStr2 = "";
		memory = "";
		operation = ' ';
		firstInput = true;
		reset = false;
		isGraphing = false;
		displayText.setText("0");
		//hide buttons
		button[1].setText("M");
		button[2].setText("R");
		button[3].setText("00");
		button[4].setText("^");
		button[5].setText("\u221A");
		button[22].setText("+/-");
		button[23].setText("=");
	}
	
	public void toggleGraphBtn() {
		boolean btnState = graphBtn.isSelected();
		graphBtn.setSelected(!btnState);
	}
	
	private void doAction(char ch) {
		//System.out.println(ch);
		String resultStr;
		
		switch (ch) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case '.':
			if (isGraphing) {
				String str = displayText.getText();
				displayText.setText(str+ch);
				break;
			}
			if (reset) {
				numStr1 = numStr2 = "";
				reset = false;
			}
			if (numStr1 == "0") numStr1="";
			if (numStr1 == "" && ch == '.') numStr1 = "0";
			if (numStr2 == "" && ch == '.') numStr2 = "0";
			if (firstInput) {
				numStr1 = numStr1 + ch;
				displayText.setText(numStr1);
			} else {
				numStr2 = numStr2 + ch;
				displayText.setText(numStr2);
			}
			break;
			
		case '+':
		case '-':
		case '*':
		case '/':
		case '%':
		case '^':
			if (isGraphing) {
				String str = displayText.getText();
				if (ch == '^') displayText.setText(str+"pow(");
				else displayText.setText(str+ch);
				break;
			}
			operation = ch;
			firstInput = false;
			numStr2="";
			reset = false;
			break;
			
		case KeyEvent.VK_BACK_SPACE:
			if (isGraphing) {
				String str = displayText.getText();
				displayText.setText(str.substring(0, str.length()-1));
				break;
			}
			if (firstInput) {
				if (numStr1.length()>0)
					numStr1 = numStr1.substring(0, numStr1.length()-1);
				if (numStr1.length() == 0) numStr1 = "0";
				displayText.setText(numStr1);
			} else {
				if (numStr2.length()>0)
					numStr2 = numStr2.substring(0, numStr2.length()-1);
				if (numStr2.length() == 0) numStr2 = "0";
				displayText.setText(numStr2);
			}
			break;
			
		case '@':
			if (isGraphing) {
				String str = displayText.getText();
				displayText.setText(str+"sqrt(");
				break;
			}
			if (firstInput) {
				numStr1 = String.valueOf(Math.sqrt(Double.parseDouble(numStr1)));
				displayText.setText(numStr1);
			} else {
				numStr2 = String.valueOf(Math.sqrt(Double.parseDouble(numStr2)));
				displayText.setText(numStr2);
			}
			break;
			
		case 's':
		case 'S':
		case ',':
			if (isGraphing) {
				String str = displayText.getText();
				displayText.setText(str+",");
				break;
			}
			if (firstInput) {
				numStr1 = String.valueOf(Double.parseDouble(numStr1)*-1);
				displayText.setText(numStr1);
			} else {
				numStr1 = String.valueOf(Double.parseDouble(numStr1)*-1);
				displayText.setText(numStr2);
			}
			break;
			
		case 'z':
		case 'Z':
		case 'x':
		case 'X':
			if (isGraphing) {
				String str = displayText.getText();
				displayText.setText(str+"x");
				break;
			}
			if (firstInput) {
				if (numStr1 != "0" && numStr1 != "") {
					numStr1 = numStr1 + "00";
					displayText.setText(numStr1);
				}
			} else {
				if (numStr2 != "0" && numStr2 != "") {
					numStr2 = numStr2 + "00";
					displayText.setText(numStr2);
				}
			}
			break;
			
		case 'g':
		case 'G':
			toggleGraphBtn();
			break;
			
		case '=':
		case KeyEvent.VK_ENTER:
			if (isGraphing) { showGraph(); break; }
			if (numStr1=="") break;
			if (numStr2==""&&operation==' ') break;
			if (numStr2=="") numStr2 = numStr1;
			resultStr = evaluate();
			displayText.setText(resultStr);
			numStr1 = resultStr;
			//numStr2 = resultStr;
			firstInput = true;
			reset = true;
			break;
			
		case 'C':
		case 'c':
			displayText.setText("0");
			numStr1 = "0";
			numStr2 = "";
			firstInput = true;
			break;
			
		case 'M':
		case 'm':
		case '(':
			if (isGraphing) {
				String str = displayText.getText();
				displayText.setText(str+"(");
				break;
			}
			memory = displayText.getText();
			break;
			
		case 'R':
		case 'r':
		case ')':
			if (isGraphing) {
				String str = displayText.getText();
				displayText.setText(str+")");
				break;
			}
			displayText.setText(memory);
			numStr1 = memory;
			memory = "";
			firstInput = false;
			break;
			
		case 'E':
		case 'e':
			System.exit(0);
			break;
		}
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		String str = String.valueOf(e.getActionCommand());
		char ch = str.charAt(0);
		doAction(ch);
	}
	
	private String evaluate() {
		final char BEEP = '\u0007';
		
		try {
			double num1 = Double.parseDouble(numStr1);
			double num2 = Double.parseDouble(numStr2);
			double result = 0.0;
			
			switch (operation) {
			case '+': result = num1+num2; break;
			case '-': result = num1-num2; break;
			case '*': result = num1*num2; break;
			case '/': result = num1/num2; break;
			case '%': result = num1%num2; break;
			case '^': result = Math.pow(num1, num2); break;
			}
			
			//String str = String.format("%.2f", result);
			return String.valueOf(result);
		}
		catch (ArithmeticException e) {
			System.out.print(BEEP);
			return "ERROR: " + e.getMessage();
		}
		catch (NumberFormatException e) {
			System.out.print(BEEP);
			if (numStr1.equals(""))
				return "ERROR: Invalid First Number";
			else
				return "ERROR: Invalid Second Number";
		}
		catch (Exception e) {
			System.out.print(BEEP);
			return "ERROR";
		}
	}
	
	private void showGraph() {
		SimpleGraph g = new SimpleGraph(displayText.getText());
		toggleGraphBtn();
	}
	
	public static void main(String[] args) {
		Calculator C = new Calculator();
	}

}
    

   SimpleGraph.java

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleBindings;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class SimpleGraph extends JPanel {
	private int bound = 10;
	private int panelSize = 300;
	private String formula;
	
	public SimpleGraph(String f) {
		setBackground(Color.WHITE);
		formula = f;
		
		JFrame wdw = new JFrame();
		wdw.setTitle("y="+formula);
		
		formula = formula.replace("pow","Math.pow");
		formula = formula.replace("sqrt","Math.sqrt");
		
		Container pane = wdw.getContentPane();
		pane.setLayout(new BorderLayout());
		
		pane.add(this,BorderLayout.CENTER);
		
		JPanel btnPanel = new JPanel(new FlowLayout());
	    JButton incrBtn = new JButton("+");
	    btnPanel.add(incrBtn);
	    incrBtn.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				// zoom in
				if (bound == 1) return;
				if (bound<=10) bound-=1;
				else bound-=10;
				repaint();
			}
	    });
	    JButton decrBtn = new JButton("-");
	    btnPanel.add(decrBtn);
	    decrBtn.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (bound<10) bound+=1;
				else bound+=10;
				repaint();
			}
	    });
	      
	    pane.add(btnPanel,BorderLayout.SOUTH);
		
		wdw.setSize(panelSize+8,panelSize+68);
		wdw.setResizable(false);
		wdw.setVisible(true);
	}
	
	public void paintComponent(Graphics g)
	{
	    super.paintComponent(g);
	    //draw basic graph
	    g.drawLine(panelSize/2, 0, panelSize/2, panelSize); // vert axis
	    g.drawLine(0, panelSize/2, panelSize, panelSize/2); // horz axis
	    g.drawString("Scale: "+bound, 0, panelSize); // bounds
	    
	    int space = (panelSize/2)/bound; //15
	    for (int b=-bound; b<bound; b++) {
	    	try {
		    	// evaluate the users equation and graph
	    		ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
		        Map<String, Object> vars = new HashMap<String, Object>();
		        
		    	double x1 = b;
		    	vars.put("x", x1);
		    	double y1 = (double)engine.eval(formula, new SimpleBindings(vars));
		    	
		    	double x2 = b+1;
		    	vars.put("x", x2);
		    	double y2 = (double)engine.eval(formula, new SimpleBindings(vars));

		    	//transform axis
		    	double xT1 = (x1*space+(panelSize/2));
		    	double xT2 = (x2*space+(panelSize/2));
		    	double yT1 = ((panelSize/2)-y1*space);
		    	double yT2 = ((panelSize/2)-y2*space);
		    	
		    	// this loop makes the curves nice and smooth
	    		for (int i=0; i<space; i++) {
	    			double mX1 = (xT1+i);
	    			double mX2 = (xT1+i+1);
	    			
	    			vars.put("x", ((mX1-(panelSize/2))/space));
			    	double mY1 = (double)engine.eval(formula, new SimpleBindings(vars));
			    	
			    	vars.put("x", (mX2-(panelSize/2))/space);
			    	double mY2 = (double)engine.eval(formula, new SimpleBindings(vars));
			    	
			    	mY1 = ((panelSize/2)-mY1*space);
			    	mY2 = ((panelSize/2)-mY2*space);
			    	
			    	//System.out.println("Segment: "+mX1+" "+mY1+" "+mX2+" "+mY2);
	    			g.setColor(Color.RED);
			    	g.drawLine((int)mX1, (int)mY1, (int)mX2, (int)mY2);
	    		}
	    		// uncomment below to draw the raw, choppy graph
	    		//g.drawLine((int)xT1, (int)yT1, (int)xT2, (int)yT2);
	    	} catch (Exception e) {System.out.println(e.getMessage());}
	    }
	}
}
    

   Instructions.txt

======================
|| Stuart Roskelley ||
======================

=====================================
Extra Features include the following:
=====================================
Shortcuts to all keys. (Listed below).
Simple memory button.
Show what's in memory and set as first number.
Equals sign will duplicate first number if followed by an operation (e.g. 5+= --> numStr2 = 5).
Equals sign keeps operation in memory so the same operation can be repeated.
Add square root.
Add Sign change.
Add two extra zeros.
Add backspace capability.
Add simple graphing (y=...).
Add zoom in and out on graph.

==========================
How to use extra features:
==========================
- For basic calculator functions, use buttons or shortcuts below.
- For the equals sign, to reach first entry listed above, input a number, hit an operator, hit equals.
- For the equals sign, to reach second entry listed above, input a number, hit an operator, hit another
  number, hit equals, hit equals again.
- To use powers, in regular mode, hit the first number, then ^, then the second number and =. In graphing
  mode, hit "pow" and then the first number, comma, second number.
- To use square root, in regular mode, hit the number and then square root. This will apply it to only
  that number. To use it in graphing, hit the "sqrt" button and then the number, then closing parenthesis.
- To graph, hit the "y=" button. This puts you into graphing mode. Either hit buttons or use shortcuts
  to formulate equation (NOTE: this only accepts well formed equations (no errors). Hit the go button
  to bring up the graph.
- To zoom in or out on the graph, hit the + or - buttons on the graph screen.

=======================================
Shortcut Keys (other than the obvious):
=======================================
=				enter or =
Go				enter or =
memory			m
return memory	r
pow				^
sqrt			@
add 00			z
Clear			c
Exit			e
+/-				s
Toggle graph	g