001 /* 002 * Calculator GUI 003 * 004 * Developed for "Rethinking CS101", a project of Lynn Andrea Stein's. 005 * For more information, see <a href="http://www.cs101.org/">the 006 * CS101 homepage</a> or email <las@olin.edu>. 007 * 008 * Copyright (C) 1996 Massachusetts Institute of Technology. 009 * Please do not redistribute without obtaining permission. 010 */ 011 package calculator; 012 import java.awt.*; 013 import java.awt.event.*; 014 import cs101.util.semaphore.IntBuffer; 015 016 /** 017 * This is an implementation of the GUI for a basic four-function 018 * calculator. It relies on a ButtonHandler (Runnable) to repeatedly 019 * call getButton() and consume the buttonIDs that the Calculator 020 * object produces. <p> 021 * 022 * This follows the interactive-control-loop design described in the 023 * early parts of PI and as a part of the 024 * <a href="http://www.cs101.org/"> 025 * Rethinking CS101 026 * </a> project of Lynn Andrea Stein's AP Group at Olin College. 027 * <p> 028 * 029 * 030 * @see ButtonHandler 031 * @see cs101.util.semaphore.IntBuffer 032 * 033 */ 034 035 public class CalculatorGUI extends Frame implements ActionListener, Calculator { 036 037 /** 038 * The "screen" of the calculator. Private -- do not use. 039 */ 040 private TextField display; 041 042 /** 043 * Synchronized storage for put/getButton. Private -- do not use. 044 */ 045 private IntBuffer buttonBuf = new IntBuffer(); 046 047 /** 048 * The Button components themselves. Private -- do not use. 049 */ 050 private Button[] Buttons = new Button[Calculator.LAST]; 051 052 // Set up the labels w/ static initializer (only need to do this once). 053 static { 054 for ( int i = 0; i < 10; i++ ) { 055 ButtonLabels[i] = String.valueOf( i ); 056 } 057 ButtonLabels[Calculator.OP_DIV] = "/"; 058 ButtonLabels[Calculator.OP_MUL] = "*"; 059 ButtonLabels[Calculator.OP_ADD] = "+"; 060 ButtonLabels[Calculator.OP_SUB] = "-"; 061 ButtonLabels[Calculator.DOT] = "."; 062 ButtonLabels[Calculator.EQUALS] = "="; 063 ButtonLabels[Calculator.CLEAR] = "clear"; 064 } 065 066 /** 067 * Initialize components and such at runtime. Automagically called 068 * by the java runtime. You should not use it. 069 */ 070 public CalculatorGUI() { 071 super("CS101 Calculator"); 072 073 this.setLayout( new GridLayout( 0, 1 ) ); 074 075 this.display = new TextField(""); 076 this.display.setEditable( false ); 077 this.display.setBackground( Color.white ); 078 this.display.setForeground( Color.blue ); 079 this.display.setFont( new Font("Monospaced", Font.BOLD, 24) ); 080 this.display.setCursor( new Cursor(HAND_CURSOR) ); 081 082 this.add( this.display ); 083 084 for ( int i = 0; i < Calculator.LAST; i++ ) { 085 this.Buttons[i] = new Button( Calculator.ButtonLabels[i] ); 086 this.Buttons[i].addActionListener(this); 087 } 088 // Layout the keypad one row at a time. 089 Panel numberPad = new Panel(); 090 numberPad.setBackground( Color.lightGray ); 091 numberPad.setForeground( Color.black ); 092 numberPad.setFont( new Font("Monospaced", Font.BOLD, 20) ); 093 numberPad.setCursor( new Cursor(HAND_CURSOR) ); 094 095 numberPad.setLayout( new GridLayout( 0, 4, 1, 1 ) ); 096 numberPad.add( this.Buttons[7] ); // Row 1 097 numberPad.add( this.Buttons[8] ); 098 numberPad.add( this.Buttons[9] ); 099 numberPad.add( this.Buttons[Calculator.OP_DIV] ); 100 numberPad.add( this.Buttons[4] ); // Row 2 101 numberPad.add( this.Buttons[5] ); 102 numberPad.add( this.Buttons[6] ); 103 numberPad.add( this.Buttons[Calculator.OP_MUL] ); 104 numberPad.add( this.Buttons[1] ); // Row 3 105 numberPad.add( this.Buttons[2] ); 106 numberPad.add( this.Buttons[3] ); 107 numberPad.add( this.Buttons[Calculator.OP_ADD] ); 108 numberPad.add( this.Buttons[0] ); // Row 4 109 numberPad.add( this.Buttons[Calculator.DOT] ); 110 numberPad.add( this.Buttons[Calculator.EQUALS] ); 111 numberPad.add( this.Buttons[Calculator.OP_SUB] ); 112 numberPad.add( new Button("") ); // Row 5 113 numberPad.add( new Button("") ); 114 numberPad.add( new Button("") ); 115 numberPad.add( this.Buttons[Calculator.CLEAR] ); // --BIG button 116 this.add( numberPad ); 117 118 this.pack(); // Set the window size, 119 this.show(); // pop it up, 120 this.validate(); // 121 this.setResizable(false); // 122 123 124 this.addWindowListener( new WindowAdapter() { 125 public void windowClosing( WindowEvent e) { 126 System.out.println("Exiting..."); 127 CalculatorGUI.this.dispose(); 128 System.exit(0); 129 } 130 }); 131 132 133 // Java 1.1 Event Model: To handle WINDOW_CLOSING event, 134 // i.e., cleanly kill this application, either need (1) the 135 // above event listener implemented as an anonymous inner 136 // class OR (2) the following line and the 137 // 'processWindowEvent' method for low-level event handling, 138 139 this.enableEvents(AWTEvent.WINDOW_EVENT_MASK); 140 } 141 142 /** 143 * Handle WINDOW_CLOSING event, i.e., cleanly kill this 144 * application. Automagically called by the java runtime. You 145 * should not use it. 146 * 147 * Other window events are passed to the superclass (default) event 148 * handling. 149 */ 150 public void processWindowEvent( WindowEvent e ) { 151 if (e.getID() == WindowEvent.WINDOW_CLOSING) { 152 System.out.println("Exiting..."); 153 this.dispose(); 154 System.exit(0); 155 } else { 156 super.processWindowEvent(e); 157 } 158 } 159 160 /** 161 * Handle button pushes by making them available to getButton. 162 * Automagically called by the java runtime. You should not use it. 163 */ 164 public void actionPerformed( ActionEvent e ) { 165 /* 166 private String whichButton = new String( 167 e.getActionCommand() ); 168 169 */ 170 // Java 1.1 Event Model: If no action command string is 171 // explicitly set, 'getActionCommand' returns the button label. 172 173 for ( int i = 0; i < Calculator.LAST; i++ ) { 174 if ( (e.getActionCommand()).equals( ButtonLabels[i] )) { 175 buttonBuf.putButton( i ); 176 break; // exit the for loop as soon as we have a match. 177 } 178 } 179 } 180 181 /** 182 * Get the next Button pressed. The return value will be an int 183 * between 0 and 9 (if the button was a number) or one of the 184 * Calculator constants. 185 * 186 * @return the next button to be handled. 187 */ 188 public int getButton() { 189 return this.buttonBuf.getButton(); 190 } 191 192 /** 193 * Get the text currently displayed on the Calculator. 194 * 195 * @return the text as a String. 196 */ 197 public String getText() { 198 return this.display.getText(); 199 } 200 201 202 /** 203 * Set the text currently displayed on the Calculator. 204 * 205 * @param newText the text to be displayed. 206 */ 207 public void setText( String newText ) { 208 this.display.setText( newText ); 209 } 210 } 211 212 /* Comments: 213 * 214 * History: 215 * $Log: CalculatorGUI.java,v $ 216 * Revision 1.2 2004/03/26 21:04:11 gus 217 * take ownership 218 * 219 * Revision 1.1 2003/07/10 21:14:43 jon 220 * Initial commit of spring03 calculator source. 221 * 222 * Revision 1.1.1.1 2002/06/05 21:56:24 root 223 * CS101 comes to Olin finally. 224 * 225 * Revision 1.3 1997/10/05 21:11:20 shong 226 * Updated for fall97, to Java 1.1 227 * changed GUI, using 1.1 Event Model 228 * 229 * Revision 1.2 1997/07/16 14:15:21 tparnell 230 * *** empty log message *** 231 * 232 * Revision 1.2 1996/10/04 19:02:26 las 233 * Fixed the location of the clear button so that it's not quite so 234 * grotesque. (I suppose that the right answer is a GridBagLayout....) 235 * 236 * Revision 1.1 1996/10/04 16:20:21 las 237 * Transformed Calculator into an application and made it a package. See 238 * STAFF_SETUP for which files are public. To run, use Calculator.Main. 239 * 240 * Specifics: 241 * Added Main.java, which starts the calculator program (both 242 * CalculatorGUI and ButtonHandler); 243 * Made Calculator an interface; 244 * Moved GUI implementation (previously in Calculator) to 245 * CalculatorGUI. 246 * Added clear button, which looks pretty gross right now. (It can 247 * be deleted in a single line, though.) 248 * 249 * Revision 1.1.1.1 1996/07/18 17:26:12 sit 250 * Import from summer 6.80s web tree 251 * 252 * 253 */ 254 255