Extending the Calculator's Functionality
The arbitrary-precision integer calculator posted here (see also the demo) is designed so that its appearance and/or
functionality may be modified without changing the distributed code.
This is accomplished by using one or both of the optional command-line
arguments when invoking the program as an application, or in passing
parameters to the applet. However, additional Java code must be
written in order to define the desired behavior.
Please note that, while any code which extends (without modifying) the
calculator software is the property of its creator, the calculator
software itself is copyrighted by Rod Howell. Please obey the
restrictions posted at the top of the download page.
Modifying the calculator model
The two calculators shown one the demo page
are two instances of the same user interface with different underlying
models. The functionality of the two models is the equivalent, but
the implementations are different, in that they use different classes
to implement large integers. Here, we describe how different models
can be defined. These models may, in fact, have different
functionality, although the user interface would probably need to be
changed in order to take advantage of this difference (see below).
A model consists of a single Java package. This package must contain
a class called CalculatorImpl which implements the interface
EDU.ksu.cis.calculator.Calculator.
Furthermore, CalculatorImpl must contain a visible constructor
accepting two arguments as follows:
- The first argument must be of type EDU.ksu.cis.calculator.CalculatorUI.
This is a reference to the user interface that is using this model.
It may be an instance of EDU.ksu.cis.calculator.DefaultUI,
or it may be an instance of a programmer-defined class as described
below.
- The second argument must be of type int. This gives the
radix that the calculator will display initially.
The CalculatorImpl class must contain the following two
methods in order to implement the interface Calculator:
- public void changeSettings(Object change, String input)
- This method is called by the user interface when the user requests a
change to some setting of the calculator. The change is encoded in
some way by the two parameters. In order for this method to be
utilized to its fullest extent, the user interface class must be
defined so as to encode any change as an Object and a String so that
this method will understand what change has been requested. DefaultUI is only
capable of encoding a change to the "Sticky bases" setting (see the User's Guide). Such a change is
encoded by passing as the first parameter a Boolean whose value is
true iff bases are to be sticky (the second parameter may be
any String). This method is responsible for recording the new setting
and notifying the user interface of any change to the value in the
display.
- public void doOperation(Operation op, String input) -
This method is called by the user interface whenever an operation needs
to be performed. The operation is passed as the first parameter (see
below). The second parameter gives the user input, if any. If there
is no user input, the second parameter is null. This method
is responsible for performing the given operation and notifying the
user interface of the resulting value to be displayed. The performing
of the operation may or may not involve any calculation. For example,
if an infix model is being defined, an addition operation will not
compute the result of the addition, because the second operand will be
unknown; however, it may compute a pending multiplication operation if
the given input is its second operand.
The above methods may throw any Exception.
Besides the class CalculatorImpl, the package must also
contain classes defining each operation that this model will support.
These classes must implement EDU.ksu.cis.calculator.Operation.
Furthermore these classes must have names that are known to the user
interface (see DefaultUI for a
list of the operation classes know to that user interface). Finally,
each of these classes must have a visible no-args constructor.
In order to implement Operation, these
classes must contain a method
public int numOperands()
which returns the number of operations needed by this operation.
In order for the doOperation method of
CalculatorImpl to be able to perform a given operation, it
must first determine the type of the Operation using the
instanceof keyword. The first type checked by
doOperation should always be EDU.ksu.cis.calculator.EncodedOperation.
An operation implementing this interface contains all the code needed
to perform the operation. Specifically, it must contain a method
public Object doOperation(Object[] operands)
All of the operands for the operation are passed as elements of the
array parameter, and the result of the operation is returned. While
this method may throw any Exception, it should throw
ArrayIndexOutOfBoundsException if an incorrect number of
operands is passed, or ClassCastException if any of the
operands are of an incorrect type.
For examples of calculator model definitions, see the source code and
API Documentation for the packages
EDU.ksu.cis.calculator.defaultmodel and
EDU.ksu.cis.calculator.javamodel, available on the download page.
Modifying the user interface
The user interface may also be modified, either independently from or
together with the model. A user interface consists of a Java class,
which must implement the interface EDU.ksu.cis.calculator.CalculatorUI.
Furthermore, this class must contain a visible constructor accepting
two parameters, as follows:
- The first parameter must be of type String. This String must
contain the name of the package containing the model (see above). The
String must be terminated by a period. The user interface is
responsible for constructing an instance of the
CalculatorImpl class in this package.
- The second parameter must be of type
javax.swing.JApplet. This is the applet (or panel) on which
the user interface will be displayed. The user interface class is
responsible for adding the necessary GUI components, together with
event handlers, to this JApplet.
The user interface class must contain the following methods in order
to implement the interface CalculatorUI:
- public String getInput() - This method returns the
current contents of its input buffer (i.e., input provided by the
user, but not yet given to the model). This is provided for the
benefit of event handlers.
- public void insert(String s) - This method inserts the
given String into the input buffer at a location determined by the
implementation. This method is provided for event handlers that
accept numeric input.
- public void setBusy(boolean b) - This method is provided
so that the user interface can be notified whether work is being done,
so that proper notification can be given to the user (e.g., by
changing the cursor).
- public void setOutput(String s, int b) - This method
sets the output to contain the given String. b is the radix
in which this string is interpreted.
- public void showError(Throwable e) - This method
displays the given Throwable in an error message. This method is
provided for event handlers which encounter exceptional conditions.
None of the above methods may throw Exceptions.
The user interface will ordinarily contain a number of event handlers.
Some of these event handlers will interact with the model by calling
the CalculatorImpl.doOperation(Operation, String) method.
Hence, there must be some mechanism by which the user interface can
construct instances of the various Operations defined in the
model package. Furthermore, each of these Operations must be
associated with some specific user action (e.g., the pressing of a
button). Thus, the code of the user interface must contain the names
of the operation classes, as well as associations between these
classes and specific events.
For an example of a user interface definition, see the source code and
API Documentation for EDU.ksu.cis.calculator.DefaultUI,
available on the Download Page.
Copyright © Rod Howell, 2001. All rights reserved.
Last updated July 27, 2001.
Rod Howell
(howell@cis.ksu.edu)