//================================================================================= // File MCalc.java jlouie 6.96 73270.1776@compuserve.com // This file should be named MCalc.java and compiled with 'javac'/'java compiler' // Title * MCalc v1.6 * // Free if distributed as is with a functioning and unaltered about box. // Thanks to W. Carlini, T. Ball, R. Scorer, W. Brogden & the folks at Java Support. // Creates an GUI AWT Mortgage Calculator // Compiled with: Sun's Mac JDK 1.02/ System 7.5.2 // Tested with: Mac Netscape 2.0javab1 and 3.0b4 // Sun's MacJDK Applet Viewer // // Known bugs and incompatabilities: // This Applet does not work with Netscape 3.0b4 (Mac), see workaround in MCalc.init() // Dialog boxes and Frame menus are not supported by Netscape 2.0jb1(Mac) // Packed Dialog boxes do not display the last item under Netscape 3.0b4 (Mac) // Modal Dialog boxes are non_modal under Netscape 2.01 (Win95) // Key filter isDigit() is buggy with Netscape 3.0b4 (Win95) // // Features not implemented: // Responding to keyboard equivalents. // Formatting numeric output (see Format() in "Core Java"). // Online help // // "New" Features: Corrects an error in MyTextField initialization // "Supports" key filters in MyTextField // Utilizes Font() class. // // Ref: "Teach Yourself Java in 21 Days", Lemay & Perkins, Sams Net // Ref: "Java in a Nutshell", David Flanagan, O'Reilly & Associates // Ref: "Core Java", Cornell & Horstmann, Sunsoft Press // Ref: "The Java Programming Language" Arnold & Gosling Addison Wesley // General Ref: "Code Complete" Steve McConnell, Microsoft Press //================================================================================= import java.awt.*; //===================================================================== // // Class * MCalc * // // Main applet class. Adds a button to a web page. // //====================================================================== public class MCalc extends java.applet.Applet { Button newCalc; public void init() // add a button to the web page { //NewCalc(); // workaround Mac Netscape 3.0b4 add(new Label("Mortgage Calculator:")); add(newCalc= new Button("New Calculator")); } public void NewCalc() { new MyFrame("MCalc"); } public boolean action(Event evt, Object obj) { if (evt.target == newCalc) { NewCalc(); return true; } return super.action(evt, obj); } } //============================================================================ // // Class * MyFrame * // // Calculator Input/Output Interface // //========================================================================== class MyFrame extends Frame { MyTextField[] textArray; // Array of four extended text boxes for input/output Label messageBox; // Calculator field for user feedback MyAbout dl; // About Dialog Box MyError err; // Error Dialog Box double dbArray[], dbResult= 0; // Array of double, stores numeric input Point p; // Stores location window static final int NO_KEY_FILTER= 0; // keyFilter Constants static final int NUMERIC_ONLY= 1; static final int DIGITS_ONLY= 2; MyFrame(String title) // Main Window Constructor { super(title); dbArray= new double[4]; textArray= new MyTextField[4]; setLayout(new GridLayout(6,2,10,10)); add(new Label("A Mortgage Calculator", Label.RIGHT)); messageBox= new Label("One Entry Must Be 0", Label.LEFT); add(messageBox); add(new Label("Principle: $", Label.RIGHT)); textArray[0]= new MyTextField("",20, NUMERIC_ONLY); add(textArray[0]); add(new Label("Annual Interest (0-100): %", Label.RIGHT)); textArray[1]= new MyTextField("",20, NUMERIC_ONLY); add(textArray[1]); add(new Label("Loan Period (Months): ", Label.RIGHT)); textArray[2]= new MyTextField("",20, DIGITS_ONLY); add(textArray[2]); add(new Label("Monthly Payments: $", Label.RIGHT)); textArray[3]= new MyTextField("0",20, NUMERIC_ONLY); add(textArray[3]); // we must instance MyTextFields _before_ this assignment textArray[0].nextField = textArray[1]; textArray[0].prevField = textArray[3]; textArray[1].nextField = textArray[2]; textArray[1].prevField = textArray[0]; textArray[2].nextField = textArray[3]; textArray[2].prevField = textArray[1]; textArray[3].nextField = textArray[0]; textArray[3].prevField = textArray[2]; Button OKbutton= new Button("OK"); add(OKbutton); add(new Button("Cancel")); MenuBar mb= new MenuBar(); Menu m= new Menu("File"); m.add(new MenuItem("About MCalc...")); m.add(new MenuItem("Close")); mb.add(m); setMenuBar(mb); p= location(); this.move(p.x + 20, p.y + 20); this.resize(400,400); // workaround this.pack(); // workaround Win95 & Netscape Font f= OKbutton.getFont(); f= new Font(f.getName(), Font.BOLD, f.getSize()); OKbutton.setFont(f); OKbutton.setBackground(Color.white); f= null; this.setBackground(Color.lightGray); this.show(); textArray[0].requestFocus(); } //================================== // * ParseString * // // Strips the input string of commas // // Use a StringBuffer to avoid multiple // memory allocations // //================================== String ParseString(String inString) { StringBuffer outString= new StringBuffer(inString.length()); for (int i=0; iaccuracy) && (i100) {throw new NumberFormatException();} // over 100% break; case 2: // Months if ((int)dbArray[i] != dbArray[i]) {throw new NumberFormatException();} // not an integer break; case 3: // Monthly Payment break; } textArray[i].setText(Double.toString(dbArray[i])); // echo changes } catch (NumberFormatException e) { dbArray[i]= 0; isError= true; textArray[i].setText("Error"); } if (dbArray[i]==0) { count +=1; //count zero entries field= i; //last zero text field } } if (isError) { DoDialogError("Invalid Entry"); messageBox.setText("Invalid Entry"); } else { if (count>1) { DoDialogError("Too Many Zero Entries"); messageBox.setText("Too Many Zero Entries"); } else { if (count<1) { DoDialogError("One Entry Must Be 0"); messageBox.setText("One Entry Must Be 0"); } else { strResult= DoAlgo(field); // finally, do the math! textArray[field].setText(strResult); messageBox.setText("Done"); } } } } //========================== // // * DoAboutBox * // // Create an about box // We create a reference to the about box to avoid multiple instances // This workaround is not necessary when Netscape supports modal dialogs // //========================== void DoAboutBox() { if (dl != null) // workaround for non-modal dialog Win95 netscape 2.01 { if (dl.isShowing()) dl.hide(); dl.dispose(); dl= null; } dl= new MyAbout(this, "About Box", true); } //========================== // // * DoDialogError * // // Create an error dialog // //========================== void DoDialogError(String inString) { messageBox.setText("Error"); // respond to user while dialog loads if (err != null) //workaround for non-modal Win95 netscape { if (err.isShowing()) err.hide(); err.dispose(); err= null; } err= new MyError(this,"Error Box", true, inString); } } //===================================================================== // // class * MyTextField * // // we extend TextField to implement proper tab key behavior // implements NO_KEY_FILTER, DIGITS_ONLY or NUMERIC_ONLY key filters // isDigit() is buggy with Netscape 3.0b4 (Win95) // //===================================================================== class MyTextField extends TextField { MyTextField nextField= null, prevField= null; private int keyFilter; static final int NO_KEY_FILTER= 0; // keyFilter Constants static final int NUMERIC_ONLY= 1; static final int DIGITS_ONLY= 2; static final int MIN_KEY= 0; static final int MAX_KEY= DIGITS_ONLY; public MyTextField(String str, int col, int keyFilter) { super(str, col); if ((keyFilterMAX_KEY)) {this.keyFilter = NO_KEY_FILTER;} else this.keyFilter= keyFilter; } // overloaded constructor, default NO_KEY_FILTER public MyTextField(String str, int col) { super(str, col); this.keyFilter= NO_KEY_FILTER; } //================================ // // * keyDown * // // override keyDown to trap tabs // //================================ public boolean keyDown(Event evt, int key) { switch (key) { case '\b': break; // pass to super.keyDown() case '\n': // ** fall through ** case '\r': // ** fall through ** case '\t': //if ((evt.modifiers & Event.SHIFT_MASK) == Event.SHIFT_MASK) if (evt.shiftDown()) // traps shift and option-shift etc. { if (prevField != null) { prevField.requestFocus(); prevField.selectAll(); return true; } } else { if (nextField != null) { nextField.requestFocus(); nextField.selectAll(); return true; } } break; // not handled, pass to super default: // not tab, return or backspace switch(keyFilter) { case DIGITS_ONLY: if (! IsDigit(key)) return true; // handle & ignore key input break; // pass to super case NUMERIC_ONLY: if (! IsNumeric(key)) return true; // handle & ignore key input break; // NO_KEY_FILTER, pass to super } } return super.keyDown(evt, key); } //=============================== // // * isDigit * // // returns true if key is digits 0-9 // buggy with Netscape 3.0b4 (Win95) // // //=============================== public boolean IsDigit(int key) { if (((key < '0') || (key >'9')) ) return false; else return true; } //=============================== // // * isNumeric * // // returns true if key is period, comma, or digits 0-9 // //=============================== public boolean IsNumeric(int key) { if ((key=='.') || (key==',') || ((key>='0') & (key<='9')) ) {return true;} else return false; } } //===================================================================== // // class * MyAbout * // // Create our About Dialog Box // //====================================================================== class MyAbout extends Dialog { Button OKbutton; Font f; MyAbout(Frame inFrame, String inString, boolean inBoolean) { super(inFrame, inString, inBoolean); setLayout(new GridLayout(3,1)); add(new Label("A Java AWT Applet! jlouie", Label.CENTER)); OKbutton= new Button("OK"); Panel pl= new Panel(); pl.setLayout(new FlowLayout(FlowLayout.CENTER,15,15)); pl.add(OKbutton); this.add(pl); this.add(new Label("73270.1776@compuserve.com", Label.CENTER)); // will not display under Netscape 3.0b4 (Mac) Point p=location(); this.move(p.x +20, p.y +20); this.resize(200,200); // workaround Win95 & Netscape this.pack(); // workaround Win95 & Netscape f= OKbutton.getFont(); f= new Font(f.getName(), Font.BOLD, f.getSize()); OKbutton.setFont(f); f= null; OKbutton.setBackground(Color.white); this.setBackground(Color.lightGray); this.show(); this.requestFocus(); } public boolean handleEvent(Event event) { switch (event.id) { case Event.WINDOW_DESTROY: this.hide(); // work around Win95 non_modal dialog return true; /*case Event.KEY_PRESS: // buggy if (event.key == '\n') { this.hide(); return true; }*/ default: return super.handleEvent(event); // calls action } } public boolean action(Event evt, Object obj) { if (evt.target == OKbutton) { if (this.isShowing()) this.hide(); // DoDialogError will this.dispose() } return true; // trap all actions } } //===================================================================== // // class * MyError * // // Create our error dialog box // We create a reference to the error box to avoid multiple instances // This workaround is not necessary when Netscape supports modal dialogs // //====================================================================== class MyError extends Dialog { Button OKbutton; Font f; MyError(Frame inFrame, String inString, boolean inBoolean, String errString) { super(inFrame, inString, inBoolean); setLayout(new GridLayout(3,1)); //setBackground(Color.blue); this.add(new Label(errString,Label.CENTER)); OKbutton= new Button("OK"); Panel pl= new Panel(); pl.setLayout(new FlowLayout(FlowLayout.CENTER,15,15)); pl.add(OKbutton); this.add(pl); this.add(new Label("ERROR", Label.CENTER)); // will not display under Netscape 3.0b4 (Mac) Point p=location(); this.move(p.x +20, p.y +20); this.resize(200,200); // workaround this.pack(); // workaround Win95 & Netscape f= OKbutton.getFont(); f= new Font(f.getName(), Font.BOLD, f.getSize()); OKbutton.setFont(f); f= null; OKbutton.setBackground(Color.white); this.setBackground(Color.lightGray); this.show(); } public boolean handleEvent(Event event) { switch (event.id) { case Event.WINDOW_DESTROY: this.hide(); // work around Win95 non_model dialog // DoError will this.dispose() return true; /*case Event.KEY_PRESS: // buggy if (event.key == '\n') { this.hide(); return true; }*/ default: return super.handleEvent(event); // calls action } } public boolean action(Event evt, Object obj) { if (evt.target == OKbutton) { if (this.isShowing()) this.hide(); // DoError will this.dispose() } return true; // modal dialog traps all actions } }