import java.applet.Applet; import java.awt.*; import java.awt.event.*; // Bill added this import for his shortcut import java.lang.reflect.*; /****************************************************************** * Bill's Calculator (Applet Version) * Copyright 2001, Bill Castrogiovanni * Feel free to use this code in whatever way you please. * It's not particularly clean code any way. * And I lifted large parts of the script from example code, myself. * * $Revision: 942 $ * $Date: 2001-04-12 21:35:38 -0700 (Thu, 12 Apr 2001) $ ******************************************************************/ /************************************** *GUI for totaling a series of numbers. **************************************/ public class CalculatorApplet extends Applet implements ActionListener { public static final int WIDTH = 200; public static final int HEIGHT = 300; public static void init(String[] args) { CalculatorApplet guiAdder = new CalculatorApplet(); guiAdder.setVisible(true); } public CalculatorApplet() { // The following lines aren't necessary in the Applet version of the application // setTitle("Calculator"); // addWindowListener(new WindowDestroyer()); setSize(WIDTH, HEIGHT); setLayout(new BorderLayout()); //This panel holds both buttonPanel and buttonPanel2 Panel mainPanel = new Panel(); mainPanel.setBackground(Color.gray); mainPanel.setLayout(new GridLayout(2, 1)); Panel buttonPanel = new Panel(); buttonPanel.setBackground(Color.gray); buttonPanel.setLayout(new GridLayout(5, 4)); // I added a second panel for a cleaner layout Panel buttonPanel2 = new Panel(); buttonPanel2.setBackground(Color.gray); buttonPanel2.setLayout(new GridLayout(3, 1)); //Bill's short cut to building the buttons String[] buttonNames = {"C", "Recall1", "Recall2", "/", "7", "8", "9", "*", "4", "5", "6", "-", "1", "2", "3", "+", "0", ".", "+/-"}; Button[] textButtonArray = new Button[Array.getLength(buttonNames)]; for (int i = 0; i < Array.getLength(textButtonArray); i++){ textButtonArray[i] = new Button(buttonNames[i]); //a hack to change the value of the "+/-" button //(so it won't be confused with the "+" button in later logic" if (i == (Array.getLength(textButtonArray) - 1)){ textButtonArray[i].setActionCommand("n"); //set this button value to "n" for "negate" } textButtonArray[i].addActionListener(this); buttonPanel.add(textButtonArray[i]); } String[] buttonNames2 = {"=", "Memory1", "Memory2"}; Button[] textButtonArray2 = new Button[Array.getLength(buttonNames2)]; for (int i = 0; i < Array.getLength(textButtonArray2); i++){ textButtonArray2[i] = new Button(buttonNames2[i]); textButtonArray2[i].addActionListener(this); buttonPanel2.add(textButtonArray2[i]); } //End Bill's short cut //add the button panels to the main panel mainPanel.add(buttonPanel); mainPanel.add(buttonPanel2); //add the main panel to the the frame add(mainPanel, "South"); Panel textPanel = new Panel(); textPanel.setBackground(Color.gray); inputOutputField = new TextField("0.0", 15); inputOutputField.setEditable(false); inputOutputField.setBackground(Color.white); textPanel.add(inputOutputField); add(textPanel, "Center"); validate(); //make sure this applet components appear. (Some browsers require this, I guess.) } public void actionPerformed(ActionEvent e) { switch (e.getActionCommand().charAt(0)) { //look at the first character in the string to determine its functionality case '.': if (! decimalFlag){ if (digitInputFlag){ inputOutputField.setText(inputOutputField.getText().concat(".")); //draw the decimal to screen } else{ inputOutputField.setText("0."); //draw the decimal to screen } digitInputFlag = true; decimalFlag = true; memoryButtonInputFlag = false; } break; case '0': if ((digitInputFlag) || (decimalFlag)){ //don't allow zeros to preface non-decimal numbers inputOutputField.setText(inputOutputField.getText().concat(e.getActionCommand())); //give user some feedback memoryButtonInputFlag = false; } break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digitInputFlag){ inputOutputField.setText(inputOutputField.getText().concat(e.getActionCommand())); //give user some feedback } else{ inputOutputField.setText(e.getActionCommand()); //give user some feedback digitInputFlag = true; } memoryButtonInputFlag = false; break; case 'M': case 'R': if (e.getActionCommand().equals("Memory1")){ memorySlot1 = inputOutputField.getText().concat(memoryLabel1); inputOutputField.setText(memorySlot1); } if (e.getActionCommand().equals("Memory2")){ memorySlot2 = inputOutputField.getText().concat(memoryLabel2); inputOutputField.setText(memorySlot2); } if (e.getActionCommand().equals("Recall1")){ inputOutputField.setText(memorySlot1); } if (e.getActionCommand().equals("Recall2")){ inputOutputField.setText(memorySlot2); } digitInputFlag = false; memoryButtonInputFlag = true; break; case 'n': // change the sign of the current number if (stringToDouble(inputOutputField.getText()) != 0){ double thisNumber = (stringToDouble(inputOutputField.getText()) * -1); inputOutputField.setText(Double.toString(thisNumber)); memoryButtonInputFlag = false; } break; default: // This is a nested switch statement // I'm nesting this because there are default behaviors // that many non-digit buttons share. Why rewrite the calls //for each function button if I can shortcut? switch (e.getActionCommand().charAt(0)) { //look at the first character in the string to determine its functionality case '+': case '-': case '*': case '/': if (firstNumberFlag){ total = stringToDouble(inputOutputField.getText()); decimalFlag = false; firstNumberFlag = false; } if (digitInputFlag || memoryButtonInputFlag){ // This is the tricky part. // In order to calculate, we need 2 seperate numbers // But, the user clicks one number, then and operator, then the second number // My trick is to store the operator in a variable, and wait for the second number // Then, when all three values have been input I call the calculate routine. total = calculate(total, operatorBuffer, stringToDouble(inputOutputField.getText())); decimalFlag = false; } operatorBuffer = e.getActionCommand(); break; case 'C': //resets all the flags/variables to their initial states total = 0; operatorBuffer = ""; decimalFlag = false; firstNumberFlag = true; break; case '=': if (firstNumberFlag) { total = stringToDouble(inputOutputField.getText()); } else { total = calculate(total, operatorBuffer, stringToDouble(inputOutputField.getText())); operatorBuffer = "";// reset any cued operators firstNumberFlag = true; } decimalFlag = false; break; default: break; //whatever } // all non-digit buttons to the following things: inputOutputField.setText(Double.toString(total)); digitInputFlag = false; memoryButtonInputFlag = false; break;// this breaks out of the original default } repaint(); } private static double stringToDouble(String stringObject) { //get rid of any memory labels if (stringObject.endsWith(memoryLabel1)){ stringObject = stringObject.substring(0, (stringObject.length() - memoryLabel1.length())); } else if (stringObject.endsWith(memoryLabel2)){ stringObject = stringObject.substring(0, (stringObject.length() - memoryLabel2.length())); } return Double.valueOf(stringObject.trim()).doubleValue(); } private static double calculate(double number1, String anOperator, double number2) { if (anOperator != "") { switch (anOperator.charAt(0)) { case '+': number1 += number2; //add break; case '-': number1 -= number2;//subtract break; case '*': number1 *= number2;//multiply break; case '/': number1 /= number2;//divide break; default: break; //whatever } } return number1; } private TextField inputOutputField; private double total = 0; private String operatorBuffer = ""; //This will store the type of math operation we will perform private static String memoryLabel1 = " (M1)"; // label displayed when the number is stored in memory private static String memoryLabel2 = " (M2)"; // label displayed when the number is stored in memory private String memorySlot1 = "0.0"; //memory slot 1 private String memorySlot2 = "0.0"; //memory slot 2 private boolean memoryButtonInputFlag = false; private boolean decimalFlag = false; private boolean digitInputFlag = false; private boolean firstNumberFlag = true; }