import java.applet.Applet; import java.awt.*; class BadOperationException extends Exception { String label; BadOperationException() { label = "E"; } } // Any class that wants to contain KeyboardButton objects // should implement this interface. This way KeyboardButton // objects could be used in more than one project, if the // class and the interface were made public. interface KeyboardOwner { public void insertString(String s); } class KeyboardButton extends Button { KeyboardOwner owner; KeyboardButton(KeyboardOwner ownerArg, String label) { // Call the parent class constructor super(label); // Record our owner owner = ownerArg; } public boolean action(Event event, Object arg) { // We've been clicked upon, so insert the text owner.insertString(getLabel()); // We're completely done processing // the action, so return 'true'. Otherwise, // the container (the applet) would also // have action called, which we don't need. return true; } } public class PrettyCalculator extends Applet implements KeyboardOwner { Button add; Button subtract; Button multiply; Button divide; Button equals; Button clear; Button lastOperation; TextField result; float current = 0; public void init() { // First, set a nicer font for the // applet, to provide larger buttons. setFont(new Font("Helvetica", Font.PLAIN, 14)); // Create a GridBagLayout manager and set it // as the layout manager for the applet GridBagLayout gridbag = new GridBagLayout(); setLayout(gridbag); // We set various members of this object // to indicate where and how large each // component should be GridBagConstraints c = new GridBagConstraints(); // For all of our components, we want the cell // to be completely filled by the component // on both axes, so we need to ask for that by // setting fill. c.fill = GridBagConstraints.BOTH; // We want to make sure java gives us any extra // space in the applet and distributes it evenly // among the components on each line. // If we don't do this, the calculator will // only be given the minimum space to accommodate // the buttons. c.weightx = 1.0; c.weighty = 1.0; // The readout should be as wide as the entire calculator, // so make sure it takes up all four cells across. c.gridwidth = GridBagConstraints.REMAINDER; // The readout is in cell 0, 0 c.gridx = 0; c.gridy = 0; result = new TextField(); gridbag.setConstraints(result, c); add(result); // Go back to one cell across c.gridwidth = 1; // New row c.gridy = 1; KeyboardButton b; b = new KeyboardButton(this, "7"); gridbag.setConstraints(b, c); add(b); b = new KeyboardButton(this, "8"); // At position 1,0 in the grid... and so it goes c.gridx = 1; gridbag.setConstraints(b, c); add(b); b = new KeyboardButton(this, "9"); c.gridx = 2; gridbag.setConstraints(b, c); add(b); divide = new Button("/"); c.gridx = 3; gridbag.setConstraints(divide, c); add(divide); // Next line c.gridy = 2; b = new KeyboardButton(this, "4"); c.gridx = 0; gridbag.setConstraints(b, c); add(b); b = new KeyboardButton(this, "5"); c.gridx = 1; gridbag.setConstraints(b, c); add(b); b = new KeyboardButton(this, "6"); c.gridx = 2; gridbag.setConstraints(b, c); add(b); multiply = new Button("*"); c.gridx = 3; gridbag.setConstraints(multiply, c); add(multiply); b = new KeyboardButton(this, "1"); // Next line c.gridy = 3; c.gridx = 0; gridbag.setConstraints(b, c); add(b); b = new KeyboardButton(this, "2"); c.gridx = 1; gridbag.setConstraints(b, c); add(b); b = new KeyboardButton(this, "3"); c.gridx = 2; gridbag.setConstraints(b, c); add(b); subtract = new Button("-"); c.gridx = 3; gridbag.setConstraints(subtract, c); add(subtract); // New row c.gridy = 4; c.gridx = 0; b = new KeyboardButton(this, "0"); gridbag.setConstraints(b, c); add(b); b = new KeyboardButton(this, "."); c.gridx = 1; gridbag.setConstraints(b, c); add(b); equals = new Button("="); c.gridx = 2; gridbag.setConstraints(equals, c); add(equals); add = new Button("+"); c.gridx = 3; gridbag.setConstraints(add, c); add(add); // Last row: one big button c.gridy = 5; c.gridx = 0; // Span the entirety of the calculator horizontally c.gridwidth = GridBagConstraints.REMAINDER; clear = new Button("Clear"); gridbag.setConstraints(clear, c); add(clear); lastOperation = null; } public boolean action(Event event, Object arg) { try { if ((event.target == add) || (event.target == subtract) || (event.target == multiply) || (event.target == divide)) { completeOperation(); lastOperation = (Button) event.target; result.setText(""); result.requestFocus(); } else if (event.target == equals) { completeOperation(); lastOperation = null; String text = Float.toString(current); result.setText(text); result.requestFocus(); } else if (event.target == clear) { current = 0; lastOperation = null; result.setText(""); result.requestFocus(); } } catch (BadOperationException e) { lastOperation = null; result.setText(e.label); } return true; } // Keep our promise to implement the KeyboardOwner interface public void insertString(String s) { // Get the text so far String text = result.getText(); // Append what was inserted text += s; // And set it back into the control result.setText(text); // Set the caret to the end by selecting // zero characters at the end of the text result.select(text.length(), text.length()); // And give the focus back to the control // so the real keyboard can be mixed with // the simulated one easily result.requestFocus(); } void completeOperation() throws BadOperationException { String text = result.getText(); Float value; try { value = Float.valueOf(text); } catch (java.lang.NumberFormatException ne) { BadOperationException oe = new BadOperationException(); throw oe; } float f = value.floatValue(); if (lastOperation == add) { current += f; } else if (lastOperation == subtract) { current -= f; } else if (lastOperation == multiply) { current *= f; } else if (lastOperation == divide) { if (f == 0) { // Prevent division by zero BadOperationException oe = new BadOperationException(); throw oe; } else { current /= f; } } else if (lastOperation == null) { current = f; } } }