Java is an object-oriented programming language with a built-in application programming interface (API) that can handle graphics and user interfaces and be used to create applications or applets. Because of its rich set of API's, similar to the Macintosh and Windows, and its platform independence, Java can also be thought of as a platform in itself. Java also has standard libraries for doing mathematics.
Much of the syntax of Java is the same as C and C++. One major difference is that Java does not have pointers. However, the biggest difference is that you must write object oriented code in Java. Procedural pieces of code can only be embedded in objects.
Applications are programs which perform the same functions as those written in other programming languages. Applets are programs which are embedded in a Web page and thus can be accessed over the Internet. Our initial focus will be on writing applications. When a program is compiled, a byte code is produced which can be read and executed by any software that can run Java.
To use this tutorial you should run and study each program as you read along, so that you can see how added features affect the program.
Objects | Constructors | Private variables | Extending a class |
Graphics | Offscreen Buffer | User Interaction | Animation |
Threads | Utility Package | ControlFrame | ControlMenu |
Table | Plot | WorldGraphics | Syntax Summary |
public class Particle { double x, y, vx, vy, mass; }This class does not do anything but can be used to describe a particle by its position, velocity, and mass. For simplicity, we will consider only two dimensions.
We need to do something to initialize a class. Every class has at least one constructor, a method which has the same name as the class. The purpose of a constructor is to perform the necessary initialization for the new object.
public class Particle { double x, y, vx, vy, mass; // these can be used by any method in the class // example of constructor method public Particle(double x, double y, double vx, double vy, double mass) { this.x = x; this.y = y; this.vx = vx; this.vy = vy; this.mass = mass; } }The above constructor allows us to specify the initial position and velocity of the particle and the value of its mass. The parameters x,y,vx,vy, and mass are the arguments of the constructor. We say that Particle is the constructor for the Particle class. We have already used the following characteristics of Java:
public class Particle { double x, y, vx, vy, mass; // examples of constructors public Particle() { } public Particle(double x, double y, double vx, double vy, double mass) { this.x = x; this.y = y; this.vx = vx; this.vy = vy; this.mass = mass; } public Particle(double x, double y) { this(x,y,0,0,1); } public Particle(double x, double y, double m) { this(x,y,0,0,m); } public Particle(double x, double y, double vx, double vy) { this(x,y,vx,vy,1); } }
We next give an example of a Particle class with some useful methods. We will omit the velocity components for now.
public class Particle { double x, y, mass; public Particle() { } public Particle(double x, double y) { this(x,y,1); } public Particle(double x, double y, double mass) { this.x = x; this.y = y; this.mass = mass; } public double getWeight() { return 9.8 * mass; } public double distanceFromOrigin() { return Math.sqrt(x*x + y*y); } }
A program consists of one or more class definitions, which should be in separate files. The name of the file should be the same as the name of the class, for example, MyApplication.java. One of these clases must define a method main. We next show a simple program that creates two objects of type Particle.
public class MyApplication { public static void main(String[] args) { Particle a = new Particle(1.0,1.0); // create an instance of Particle called a System.out.println(a.distanceFromOrigin()); System.out.println(a.mass); Particle b; b = new Particle(); b.x = 2.0; b.y = 3.0; b.mass = 3; System.out.println(b.distanceFromOrigin()); System.out.println(b.mass); System.out.println(b.getWeight()); } }
Java uses three explicit keywords and one implied keyword to set the boundaries in a class. The default access specifier for variables and methods is "package visibility" which means that all the other classes in the current package have access to them. Packages are Java's way of making libraries and will be discussed later. The specifier public provides access to anyone, private provides access only to methods within the same class, and protected provides access to methods in the same package and to all subclasses even if they are in different packages.
Ideally, the variables in the Particle class should be declared private. Make x private and see what happens when you run MyApplication.
If we declare x, y, and mass as private variables, we have to write methods in Particle so that another class can access the variable information in Particle. For simplicity, we will consider only the variable x. Our particle class becomes:
public class Particle { private double x; private double mass; public Particle(double x, double mass) { this.x = x; this.mass = mass; } public Particle(double x) { this(x, 1.0); } public double getX() { return x; } public void setX(double newX) { x = newX; } public double getWeight() { return 9.8 * mass; } public double distanceFromOrigin() { return Math.abs(x); } }
Note the new methods getX and setX. They are used in the following.
public class MyApplication { public static void main(String[] args) { Particle p = new Particle(10.0, 2.0); System.out.println(p.distanceFromOrigin()); System.out.println(p.getX()); // would have written p.x if x were public System.out.println(p.getWeight()); p.setX(3.0); // change value of x System.out.println(p.getX()); System.out.println(p.distanceFromOrigin()); } }
Now that we have defined a particle class, we can extend it to consider charged particles for example. That is, we want a new class ChargedParticle, that has all the functionality of Particle, but also has the ability to have a charge. We can implement ChargedParticle as an extension or subclass of Particle as shown below.
public class ChargedParticle extends Particle { // magnitude of electron charge in Coulombs public static final double ELQ = 1.602e-19; private int charge; public ChargedParticle(double x,double y, double mass, int charge) { super(x,y,mass); // constructor for Particle this.charge = charge; } public int getCharge() { return charge; } public void setCharge(int newCharge) { charge = newCharge; } public static int netCharge(ChargedParticle a, ChargedParticle b) { return a.charge + b.charge; } }An example of the use of this new class is given below.
public class MyApplication { public static void main(String[] args) { ChargedParticle a = new ChargedParticle(10.0,0,0,1); System.out.println(a.distanceFromOrigin()); System.out.println(a.getCharge()); System.out.println(ChargedParticle.ELQ*a.getCharge()); ChargedParticle b = new ChargedParticle(-5.0,0,0,-1); System.out.println(b.distanceFromOrigin()); System.out.println(ChargedParticle.netCharge(a,b)); b.setCharge(3); System.out.println(ChargedParticle.netCharge(a,b)); } }
The following example illustrates the nature of static variables:
public class Test { public static int x = 0; public int y = 0; public String showxandy() { return "x = " + x + ", y = " + y; } public static void main(String[] args) { Test a = new Test(); Test b = new Test(); a.x = 5; // static variable a.y = 12; // instance variable System.out.println(a.showxandy()); // outputs 5, 12 b.x = 7; b.y = 13; System.out.println(a.showxandy()); // outputs 7, 12 System.out.println(b.showxandy()); // outputs 7, 13 Test.x = 2; System.out.println(a.showxandy()); // outputs 2, 12 System.out.println(b.showxandy()); // outputs 2, 13 } }The (static) x variable belongs to class Test and hence belongs to a and b. In contrast, y belongs to the instances of the class test and hence a.y and b.y are distinct variables.
The String type is unique among all classes in that it is the only class to support an
operator: the + operator can be used to concatenate strings. When a number is concatenated with a
string, the number is converted to a string.
A powerful feature of Java is its simple to use graphics. As an example we will draw the
trajectory of a particle in projectile motion. To do this we add to Particle the method
step to integrate the equations of motion one time step forward. The arguments of
step are the time step and the Force on the particle, which is defined below in another
class. We also add other methods which will be useful.
The step method uses the Euler-Richardson integration algorithm. The first time the algorithm is
used we need to compute the acceleration at the beginning of the interval. After that we can use the
acceleration computed at the end of the previous interval. Note how this is used in the step
method to refer to the Particle itself, and then in Force we use the argument Particle to get the
particle's mass.
The class which draws the trajectory is given below.
When you click on another application covering up the
frame, and then come back to your program, Java automatically calls paint.
This is nice, however in the above program it means that you must recompute the
trajectory. A better approach is to first draw to an offscreen image buffer and then blast
this buffer to the screen. As long as the buffer is saved no new calculations are done. First
we will show how this is done for the above ParticleSystem class and then we will
show an example where it is more useful.
Offscreen buffers are useful when we want the user to be able to draw more than one trajectory
without running the program over again. To do this we want the user to interact
with the program. This feature is very easy to accomplish in Java using
components such as Buttons, TextFields, and Menus. Below we show how to use a TextField
to receive a number from the user. We put the TextField on a separate Frame and use an
actionListener to detect whether the user enters a number in the TextField. The number
entered will be the friction coefficient, b,used in a drag force of the form -bv.
The following modification of ParticleSystem uses FrictionInput.
We now return to a single trajectory and discuss animation. Instead of showing the
trajectory we will simply show a ball as it moves. The following code does this so that there
is very little flicker. We have reduced the time step so that the motion of the ball will be
slowed down.
The basic stategy used above is to define three rectangles. One containing the old
position of the ball, one containing the new position, and one which is the union of the two.
Then we clear the buffer of this latter rectangle, and draw our new ball. We then draw our image to the screen.
Note how we grab the Graphics object for the screen within calculateTrajectory instead of using
repaint. This avoids some of the flickering that would occur from clearing the Frame. Often we want the user to be able to interupt a simulation while it is running, and then
start it going again. For example, we might want to know the coodinates of our ball at some
instant while we are watching it. One can use Threads to accomplish this. Basically, a
Thread is a process whcih is running parallel to another process. Below we set up a Thread
and use a MouseListener to interupt the program. The interface Runnable
contains the methods we need to start, stop, and run the Thread.
We have modified calculateTrajectory so that it only computes and draws one
step. We have eliminated the while statement. Instead control of the trajectory is
given to the run method of the Thread runner. Note the code within this
method. The try catch statement is used to interupt the Thread for 5 milliseconds to
check to see if any event occurred. The MouseListener checks for events. In this case we can
stop the motion by moving the mouse outside the Frame, and start it again by moving it into
the Frame. If the mouse is clicked we write the x and y coodinates of the ball at the
location of the mouseclick, redraw the ball, and stop the motion. We now provide the following general purpose classes. You can use these
classes without knowing the details of how they are implemented. The
classes are part of a Java package called simphy. To use these
files you need to add import simphy.*; to any file using classes in the
package. Arrays are used heavily in the classes shown below. Note how they are
declared, instantiated, and in many cases initiated. To modify any of these
classes you can write your own which extends the class.
Graphics
public class Particle {
private double x,y,vx,vy,ax,ay;
private double mass = 1.0;
private boolean firststep = true;
public Particle(double x, double y, double vx, double vy) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
}
public double getMass() {
return mass;
}
public void setMass(double mass) {
this.mass = mass;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getVX() {
return vx;
}
public double getVY() {
return vy;
}
public double getAX() {
return ax;
}
public double getAY() {
return ay;
}
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
public void setVX(double vx) {
this.vx = vx;
}
public void setVY(double vy) {
this.vy = vy;
}
public void step(double dt, Force f) {
if(firststep) {
ax = f.getfx(x,y,vx,vy,this)/mass; // acceleration at beginning of interval
ay = f.getfy(x,y,vx,vy,this)/mass;
firststep = false;
}
double vxm = vx + 0.5*ax*dt; // velocity at middle of interval
double vym = vy + 0.5*ay*dt;
double xm = x + 0.5*vx*dt; // position at middle of interval
double ym = y + 0.5*vy*dt;
double axm = f.getfx(xm,ym,vxm,vym,this)/mass;
double aym = f.getfy(xm,ym,vxm,vym,this)/mass;
vx += axm*dt; // velocity at end of interval
vy += aym*dt;
x += vxm*dt; // position at end of interval
y += vym*dt;
ax = f.getfx(x,y,vx,vy,this)/mass; // acceleration at end of interval
ay = f.getfy(x,y,vx,vy,this)/mass;
}
}
public class Force {
private final static double g = 9.8;
double b = 0; // used in drag force
public void setb(double b) {
this.b = b;
}
public double getfx(double x, double y, double vx, double vy, Particle p) {
return -b*vx;
}
public double getfy(double x, double y, double vx, double vy, Particle p) {
return -b*vy - g*p.getMass();
}
}
import java.awt.*;
public class ParticleSystem extends Frame {
public static void main(String[] args) {
ParticleSystem ps = new ParticleSystem(); // set up window for application
}
public ParticleSystem() { // constructor
setSize(512, 342);
setVisible(true);
}
public void paint(Graphics g) {
setBackground(Color.white);
calculateTrajectory(g);
}
private void calculateTrajectory(Graphics g) {
final double tmax = 10.0;
final double dt = 0.5;
Particle p = new Particle(0.0, 200.0, 40.0, 25.0);
Force f = new Force();
g.setColor(Color.blue);
double time = 0.0;
while (time < tmax) {
g.drawOval((int)p.getX(),
getSize().height - (int)p.getY(), 10, 10); //draw circle of diameter 10 pixels
p.step(dt,f);
time += dt;
}
}
}
Offscreen buffers
import java.awt.*;
public class ParticleSystem extends Frame {
Image offscreen;
public static void main(String[] args) {
ParticleSystem ps = new ParticleSystem(); // set up window for application
}
public ParticleSystem() { // constructor
setSize(512, 342);
setVisible(true);
offscreen = createImage(getSize().width, getSize().height);
calculateTrajectory();
}
public void paint(Graphics g) {
setBackground(Color.white);
g.drawImage(offscreen, 0, 0, this); // draw image onto screen
}
public void calculateTrajectory() {
final double tmax = 10.0;
final double dt = 0.5;
Graphics g = offscreen.getGraphics();
g.setColor(Color.blue);
Particle p = new Particle(0.0, 200.0, 40.0, 25.0);
Force f = new Force();
double time = 0.0;
while (time < tmax) {
g.drawOval((int)p.getX(), getSize().height - (int)p.getY(), 10, 10);
p.step(dt,f);
time += dt;
}
}
}
User Interaction
import java.awt.*;
import java.awt.event.*; // needed for actionListener
class FrictionInput extends Frame {
TextField tf;
Label l;
ParticleSystem ps;
public FrictionInput (ParticleSystem ps) {
this.ps = ps;
setUpFrame();
}
public void setUpFrame() {
setTitle("Friction Input");
setSize(200,100);
setLocation(400,50);
setLayout(null); // not using any layout manager
l= new Label("Friction Coefficient"); // new label for textfield
l.setSize(150,20);
l.setLocation(30,70);
add(l); // add label
tf = new TextField(); // new textfield
tf.addActionListener( new T()); // add listener
tf.setSize(50,20);
tf.setLocation(30,40);
add(tf); // add textfield
setVisible(true);
}
class T implements ActionListener { // Internal class
public void actionPerformed(ActionEvent e) {
Double R = new Double(tf.getText().trim());
ps.calculateTrajectory(R.doubleValue());
}
}
}
import java.awt.*;
public class ParticleSystem extends Frame {
private Image offscreen;
private int counter = 0; // used to change color for each trajectory
public static void main(String[] args) {
ParticleSystem ps = new ParticleSystem(); // set up window for application
FrictionInput fi = new FrictionInput(ps); // set up window for application
}
public ParticleSystem() { // constructor
setSize(512, 342);
setVisible(true);
offscreen = createImage(getSize().width, getSize().height);
}
public void paint(Graphics g) {
setBackground(Color.white);
g.drawImage(offscreen, 0, 0, this); // draw image onto screen
}
public void calculateTrajectory(double b) {
final double tmax = 10.0;
final double dt = 0.5;
Graphics g = offscreen.getGraphics(); // create buffer
changeColor(g);
Particle p = new Particle(0.0, 200.0, 40.0, 25.0);
Force f = new Force();
f.setb(b);
double time = 0.0;
while (time < tmax) {
g.drawOval((int)p.getX(), getSize().height - (int)p.getY(), 10, 10);
p.step(dt,f);
time += dt;
}
repaint();
}
public void changeColor(Graphics g) {
switch(counter++) { //counter increased by 1
case 0: g.setColor(Color.red);break;
case 1: g.setColor(Color.blue);break;
case 2: g.setColor(Color.green);break;
case 3: g.setColor(Color.yellow);break;
case 4: g.setColor(Color.magenta);break;
case 5: g.setColor(Color.orange);break;
case 6: g.setColor(Color.cyan);break;
case 7: g.setColor(Color.pink);break;
default : g.setColor(Color.black);
}
}
}
if ( x < 0) {
y = 20;
x = 10;
}
if ( x < 0 )
y = 10; // braces not needed for single statement
else
y = 20;
if ( x < 0 )
y = 10;
else if ( x > 0)
y = 20;
else
y = 30;
Animation
import java.awt.*;
public class ParticleSystem extends Frame {
Image offscreen;
public static void main(String[] args) {
ParticleSystem ps = new ParticleSystem(); // set up window for application
ps.calculateTrajectory();
}
public ParticleSystem() { // constructor
setSize(512, 342);
setVisible(true);
offscreen = createImage(getSize().width, getSize().height);
}
public void paint(Graphics g) {
setBackground(Color.white);
g.drawImage(offscreen,0,0,this);
}
public void calculateTrajectory() {
final double tmax = 10.0;
final double dt = 0.005;
Graphics b = offscreen.getGraphics();
Particle p = new Particle(0.0, 200.0, 40.0, 25.0);
Force f = new Force();
double time = 0.0;
while (time < tmax) {
Rectangle oldRect = new Rectangle((int)p.getX(),getSize().height -(int)p.getY(),11,11);
p.step(dt,f);
time += dt;
Rectangle newRect = new Rectangle((int)p.getX(),getSize().height -(int)p.getY(),11,11); // new region of ball
Rectangle r = newRect.union(oldRect); // new plus old region
b.clearRect(r.x,r.y,r.width,r.height); // clear new plus old region on buffer
b.fillOval((int)p.getX(), getSize().height - (int)p.getY(), 10, 10);
Graphics g = getGraphics();
g.drawImage(offscreen,0,0,this);
}
}
}
Threads
import java.awt.*;
import java.awt.event.*;
public class ParticleSystem extends Frame implements MouseListener, Runnable {
Image offscreen;
Graphics gb;
Particle p;
Force f;
boolean running = false;
Thread runner;
public static void main(String[] args) {
ParticleSystem ps = new ParticleSystem(); // set up window for application
}
public ParticleSystem() { // constructor
setSize(512, 342);
setVisible(true);
offscreen = createImage(getSize().width, getSize().height);
p = new Particle(0.0, 200.0, 40.0, 25.0);
f = new Force();
gb = offscreen.getGraphics();
start();
addMouseListener(this);
}
public void paint(Graphics g) {
setBackground(Color.white);
g.drawImage(offscreen,0,0,this);
}
public void start() {
runner = new Thread(this);
runner.start();
}
public void stop() {
runner.stop();
}
public void run() {
while(true) {
try {Thread.sleep(5);} // delay 5 msec between updates
catch (InterruptedException e){};
if(running) calculateTrajectory();
}
}
public void mouseClicked(MouseEvent e) {
Graphics g = getGraphics();
g.clearRect(0,0,getSize().width, getSize().height);
g.fillOval((int)p.getX(), getSize().height - (int)p.getY(), 10, 10);
g.drawString("x = " + String.valueOf(p.getX()),e.getX(),e.getY());
g.drawString("y = " + String.valueOf(p.getY()),e.getX(),e.getY() + 30);
running = false;
}
public void mouseEntered(MouseEvent e) {running = true;}
public void mouseExited(MouseEvent e) {running = false;}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void calculateTrajectory() {
private final double dt = 0.005;
Rectangle oldRect = new Rectangle((int)p.getX(),getSize().height -(int)p.getY(),11,11);
p.step(dt, f);
time += dt;
Rectangle newRect = new Rectangle((int)p.getX(),getSize().height -(int)p.getY(),11,11);
Rectangle r = newRect.union(oldRect);
gb.clearRect(r.x,r.y,r.width,r.height);
gb.fillOval((int)p.getX(), getSize().height - (int)p.getY(), 10, 10);
Graphics g = getGraphics();
g.drawImage(offscreen,0,0,this);
}
}
Utility Package
Constructors and other methods for general purpose classes.
//constructors
public ControlFrame(MySimulation S, String lstring[], String bstring[])
public ControlFrame(MySimulation S, String lstring[], double x[], String bstring[])
// use if have initial values x[]
/* MySimulation implements Simulation
lstring is an array of names for the labels under the TextFields
x is an array of initial values for the TextFields
bstring is an array of names for the Buttons
You can also use the following methods to place values in the TextFields
*/
public void setText(int k, String s)
public void setText(int k, int x)
public void setText(int k, double x)
//constructors
public ControlMenu(MySimulation S, String lstring[], String bstring[])
public ControlMenu(MySimulation S, String lstring[], double x[], String bstring[]) // use if have
initial values
/* MySimulation implements Simulation
lstring is an array of names for the parameter menu
x is an array of initial values for the parameters
bstring is an array of names for the action menu
ControlMenu uses InputDialog class.
*/
public interface simulation
public void buttonAction(int k);
public void textAction(int k, double x);
public void menuAction(int k);
public void dialogAction(int k, double x);
//constructor
public Table(String TableName String h[]) // h is an array of table headings
// methods
public void setHeadings(String h[]) // display new table headings
public void setFormat(String pattern[],int FieldSize)
/* Set format for table entries. Fieldsize is maximum size for each number, pattern[k]
is the pattern for kth number. Ex. "#.000" prints 3 decimal places. */
public void setEntry(int i, double x) // set ith value equal to x for next row to be displayed
public void setEntry(double x0, double x1) // set first two values
public void setEntry(double x0, double x1, double x2) // set first three values
public void setEntry(double x0, double x1, double x2, double x3) // set first four values
public void addEntries() // display next row
//constructors
public Plot(String title, String xLabel, String yLabel, int nAxes,
double xmin,double xmax, double ymin, double ymax)
public Plot(String title, String xLabel, String yLabel, int nAxes,
double xmin,double xmax, double ymin, double ymax, int symbolSize, String symbolType) {
public Plot(int nAxes,double xmin,double xmax, double ymin, double ymax) {
/* nAxes = 1, one bottom horizontal axis, ymin should = 0
nAxes = 2, one left vertical axis, one bottom horizontal axis, xmin and ymin should = 0
nAxes = 3, one center vertical axis, one bottom horizontal axis, xmin should = -xmax, ymin should = 0
nAxes = 4, crossed axes, xmin should = -xmax and ymin should = -ymax
nAxes = 5, crossed axes, only x > 0, xmin should = 0 and ymin should = -ymax
nAxes = anything else, no axes drawn.
symbolType = "fillsquare" or "opensquare" or "opencircle" or "fillcircle"
symbolSize = 1 for point (default), otherwise gives size in pixels */
public void plotPoints(double x[], double y[]);
//constructor
public WorldGraphics(String title,
double xmin,double xmax, double ymin, double ymax) {
(xmin,ymin) are the coordinates for the lower left hand corner of the Frame.
(xmax,ymmax) are the coordinates for the upper right hand corner of the Frame.
methods have the same name as those in the Jave Graphics class.
A test example of how these classes are instantiated is shown below. Try running
this program and testing the Buttons, TextFields, and menu items. Find the code
in the program for the things you see on the screen.
import simphy.*;
public class Utilities {
public static void main(String args[]) {
Utilities u = new Utilities();
}
public Utilities() {
String h[] = {"first","second","third"};
Table tb = new Table("test",h);
String pattern[] = {"#.0000", "#.00","#.000"};
tb.setFormat(pattern,10);
tb.setEntry(0,3.173);
tb.setEntry(1,999.9173);
tb.setEntry(2,3891.73);
tb.addEntries();
tb.setEntry(3317.3,99.173,817.3);
tb.addEntries();
MySimulation S = new MySimulation();
String lString[] = {"zero", "one", "two","three", "four", "five","six", "seven", "eight"};
String bString[] = {"A", "B", "C","D", "E", "F","G", "H", "I"};
double initialP[] = { 1,2,3,4,5,6,7,8,9};
ControlFrame cf = new ControlFrame(S,lString,initialP,bString);
ControlMenu cm = new ControlMenu(S,lString,initialP,bString);
WorldGraphics v = new WorldGraphics("Visualization",0,10,0,10);
v.setMenuBar(cm.sBar);
S.notify(cm);
S.notify(v);
S.notify(cf);
}
}
An example of a Simulation class is shown below. If performs a number of arbitrary operations and
shows communication between the different objects using the notify methods. Note that because
it implements Simulation it must include implementations of the methods in the
Simulation interface. This insures that ControlFrame and ControlMenu will work
properly.
import java.awt.*;
import simphy.*;
public class MySimulation implements Simulation{
ControlMenu cm;
ControlFrame cf;
WorldGraphics v;
public void buttonAction(int k) {
double x[] = {0,1,2,3,4};
double y[] = {0,1,2,3,4};
switch(k) {
case 0: Plot p = new Plot("y vs x","xxxx","yyyy",1,-5,5,0,5);p.plotPoints(x,y);break;
case 1: Plot p1 = new Plot("y vs x","xxxx","yyyy",2,-5,5,0,5);p.plotPoints(x,y);break;
case 2: Plot p2 = new Plot("y vs x","xxxx","yyyy",3,-5,5,0,5);p.plotPoints(x,y);break;
case 3: Plot p3 = new Plot("y vs x","xxxx","yyyy",4,-5,5,0,5);p.plotPoints(x,y);break;
}
}
public void textAction(int k, double x) {
System.out.println(x);
cf.setText(0,x);
cf.setText(1,(int) x);
cf.setText(2,"hello " + String.valueOf(k));
}
public void menuAction(int k) {
switch(k) {
case 0: v.drawRect(5,5,4,4.0); break;
case 1: v.drawString("good job", 7.0,2.0);break;
case 2: v.drawLine(0,0,10,10);break;
case 3: v.drawRect(200,200,100,100);break;
case 4: v.drawCircle(5,5,3);break;
case 5: v.clearRect(0,0,10,10);break;
case 6: v.setColor("yellow");break;
case 7: v.setColor("green");break;
case 8: v.setColor("random");break;
}
cf.texts[1].setText(String.valueOf(k)); // shows which menu selected in a TextField
}
public void dialogAction(int k, double x) {
System.out.println(x);
}
public void notify(ControlMenu cm) {
this.cm = cm;
}
public void notify(ControlFrame cf) {
this.cf = cf;
}
public void notify(WorldGraphics v ) {
this.v = v;
}
}
Class and interface Listings
package simphy;
public interface Simulation { // used with ControlFrame or ControlMenu
public void buttonAction(int k);
public void textAction(int k, double x);
public void menuAction(int k);
public void dialogAction(int k, double x);
}
package simphy;
import java.awt.*;
import java.awt.event.*;
public class ControlFrame extends Frame {
public TextField texts[];
Label labels[];
Button buttons[];
Simulation S;
String lString[], bString[];
double x[];
public ControlFrame(Simulation S, String lString[], String bString[]) {
this.S = S;
this.lString = lString;
this.bString = bString;
int nT = lString.length;
x = new double[nT];
for(int i = 0; i < nT;i++)
x[i] = 0.0;
setUpFrame();
}
public ControlFrame(Simulation S, String lString[], double x[], String bString[]) {
this.S = S;
this.lString = lString;
this.bString = bString;
this.x = x;
setUpFrame();
}
public void setUpFrame() {
int ix = 20, iy = 20,bxT = 100,by = 20, ysep = 80, lsep = 20 ;
int fSize = 0, bx;
int nT = lString.length; // number of textfields
int nB = bString.length; // number of buttons
for (int i = 0; i < nB; i++)
fSize += 20 + max(bString[i].length()*10,bxT);
for (int i = 0; i < nT; i++)
fSize += 20 + max(lString[i].length()*10,bxT);
if(fSize < 500)
setSize(fSize, ysep);
else {
setSize(500, (1 + fSize/500)*ysep);
fSize = 500;
}
setTitle("Controls");
this.S = S;
setLayout(null);
texts = new TextField[nT]; // new array of textfields
labels = new Label[nT]; // new array of labels
buttons = new Button[nB]; // new array of buttons
for(int i = 0; i < nB;i++) {
bx = max(bString[i].length()*10,bxT); // button size
if(ix + bx + 20 > fSize){
ix = 20;
iy += ysep;
}
buttons[i] = new Button(bString[i]); // new button
buttons[i].addActionListener(new B(i)); // add listener
buttons[i].setSize(bx,by);
buttons[i].setLocation(ix,iy);
add(buttons[i]); // add button
ix += bx + 20;
}
for(int i = 0; i < nT;i++) {
bx = max(lString[i].length()*10,bxT); // label size
if(ix + bx + 20 > fSize){
ix = 20;
iy += ysep;
}
labels[i]= new Label(lString[i]); // new label for textfield
labels[i].setSize(bx,by);
labels[i].setLocation(ix,iy+lsep);
add(labels[i]); // add label
if( (int) x[i] == x[i])
texts[i]= new TextField(String.valueOf( (int) x[i])); // new textfield
else
texts[i]= new TextField(String.valueOf(x[i])); // new textfield
texts[i].addActionListener( new T(i)); // add listener
texts[i].setSize(bxT,by);
texts[i].setLocation(ix,iy);
add(texts[i]); // add textfield
ix += bx + 20;
}
setVisible(true);
}
private int max(int a, int b) {
if ( a > b)
return a;
else
return b;
}
public void setText(int k, String s) {
texts[k].setText(s);
}
public void setText(int k, int x) {
texts[k].setText(String.valueOf(x));
}
public void setText(int k, double x) {
texts[k].setText(String.valueOf(x));
}
// Inner classes
class B implements ActionListener {
int k; // kth button
public B(int k) {
this.k = k;
}
public void actionPerformed(ActionEvent e) {
S.buttonAction(k);
}
}
class T implements ActionListener {
int k; // kth TextField
public T(int k) {
this.k = k;
}
public void actionPerformed(ActionEvent e) {
Double R = new Double(texts[k].getText().trim());
S.textAction(k,R.doubleValue());
}
}
}
package simphy;
import java.awt.*;
import java.awt.event.*;
public class ControlMenu {
public MenuBar sBar; // declare menubar
Menu bMenu,tMenu; // declare two menus
MenuItem bItems[]; // declare array of menu items
MenuItem tItems[]; // declare array of menu items
Simulation S;
String lString[], bString[];
double x[];
public ControlMenu(Simulation S, String lString[], String bString[]) {
this.S = S;
this.lString = lString;
this.bString = bString;
int nT = lString.length;
x = new double[nT];
for(int i = 0; i < nT;i++)
x[i] = 0.0;
setUpMenu();
}
public ControlMenu(Simulation S, String lString[], double x[], String bString[]) {
this.S = S;
this.lString = lString;
this.bString = bString;
this.x = x;
setUpMenu();
}
public void setUpMenu() {
sBar = new MenuBar(); // assign menubar
bMenu = new Menu("Actions"); // assign menu
tMenu = new Menu("Parameters"); // assign menu
sBar.add(bMenu); // add menu to menubar
sBar.add(tMenu); // add menu to menubar
int nB = bString.length;
bItems = new MenuItem[nB]; // assign array of menu items
int nT = lString.length;
tItems = new MenuItem[nT]; // assign array of menu items
for(int i = 0; i < nT;i++) {
tItems[i] = new MenuItem(lString[i]); // assign menu item to array element
tItems[i].addActionListener( new T(i));
tMenu.add(tItems[i]); } // add menu item to menu
for(int i = 0; i < nB;i++) {
bItems[i] = new MenuItem(bString[i]); // assign menu item to array element
bItems[i].addActionListener( new B(i));
bMenu.add(bItems[i]); } // add menu item to menu
}
class B implements ActionListener {
int k;
public B(int k) {
this.k = k;
}
public void actionPerformed(ActionEvent e) {
S.menuAction(k);
}
}
class T implements ActionListener {
int k;
public T(int k) {
this.k = k;
}
public void actionPerformed(ActionEvent e) {
InputDialog d = new InputDialog(S,k,lString[k],x);
}
}
}
package simphy;
import java.awt.*;
import java.awt.event.*;
class InputDialog extends Frame { // Used with ControlMenu
TextField newValueText;
double x[];
public InputDialog(Simulation S,int k, String lString, double x[]) {
this.x = x;
setTitle("Dialog Box");
setSize(250,250);
setLocation(50,50);
setLayout(null);
Label label = new Label("Enter new " + lString);
label.setSize(150,20);
label.setLocation(50,20);
add(label);
Button b1 = new Button("Okay");
b1.addActionListener( new OkayClass(k,S));
Button b2 = new Button("Cancel");
b2.addActionListener( new CancelClass());
b1.setLocation(30,80);
b2.setLocation(150,80);
b1.setSize(70,20);
b2.setSize(70,20);
add(b1);
add(b2);
newValueText = new TextField(String.valueOf(x[k]));
newValueText.setSize(80,20);
newValueText.setLocation(50,50);
add(newValueText);
setVisible(true);
}
class OkayClass implements ActionListener{
int k;
Simulation S;
public OkayClass(int k, Simulation S) {
this.k = k;
this.S = S;
}
public void actionPerformed(ActionEvent e) {
String s = newValueText.getText();
Double R = new Double(s.trim());
S.dialogAction(k,R.doubleValue());
x[k] = R.doubleValue();
setVisible(false);
dispose();
}
}
class CancelClass implements ActionListener{
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
}
}
}
package simphy;
import java.awt.*;
import java.text.*;
public class Table extends Frame {
protected double entry[];
int n;
public TextArea t;
DecimalFormat number[];
int FieldSize = 10;
public Table(String TableName, String h[]) { // sets up Table with default formats
n = h.length;
entry = new double[n];
number = new DecimalFormat[n];
setTitle(TableName);
setSize(500,500);
t = new TextArea();
add(t);
setVisible(true);
setHeadings(h);
String pattern[] = new String[n];
for(int i = 0; i < n ; i++)
pattern[i] = "#.000";
setFormat(pattern,FieldSize);
}
public void setHeadings(String h[]) {
int len;
setFont(new Font("Monospaced",Font.BOLD,10));
for(int i = 0; i < n ; i++) {
len = h[i].length();
if(len < FieldSize)
for(int j = 0; j < FieldSize-len;j++) h[i] = " " + h[i];
t.append(h[i] + "\t");
}
t.append("\n" + "\n");
}
public void setFormat(String pattern[],int FieldSize) {
this.FieldSize = FieldSize;
for(int i = 0; i < n ; i++)
number[i] = new DecimalFormat(pattern[i]);
}
public void println(String S) {
t.append(S + "\n");
}
public void addEntries() {
int len;
String s;
setFont(new Font("Monospaced",Font.PLAIN,10));
for(int i = 0; i < n ; i++) {
s = number[i].format(entry[i]);
len = s.length();
if(len < FieldSize)
for(int j = 0; j < FieldSize-len;j++) s = " " + s;
t.append(s + "\t");
}
t.append("\n");
}
public void setEntry(int i, double x) {
entry[i] = x;
}
public void setEntry(double x0, double x1) {
entry[0] = x0;
entry[1] = x1;
}
public void setEntry(double x0, double x1, double x2) {
entry[0] = x0;
entry[1] = x1;
entry[2] = x2;
}
public void setEntry(double x0, double x1, double x2, double x3) {
entry[0] = x0;
entry[1] = x1;
entry[2] = x2;
entry[3] = x3;
}
}
package simphy;
import java.awt.*;
public class Plot extends Frame{
double scalex,scaley,xmin,ymin,xmax,ymax;
int nAxes;
String xLabel,yLabel;
int mg = 30;
int xSize,ySize;
int symbolSize;
String symbolType;
Image buffer;
Graphics b;
public Plot(String title, String xLabel, String yLabel, int nAxes,
double xmin,double xmax, double ymin, double ymax, int symbolSize, String symbolType) {
this.nAxes = nAxes;
this.xLabel = xLabel;
this.yLabel = yLabel;
this.xmin = xmin;
this.ymin = ymin;
this.xmax = xmax;
this.ymax = ymax;
this.symbolSize = symbolSize;
setTitle(title);
setSize(400,400);
xSize = size().width;
ySize = size().height;
setLocation(150,150);
setVisible(true);
setScale();
buffer = createImage(getSize().width,getSize().height);
b = buffer.getGraphics();
setAxes();
}
public Plot(String title, String xLabel, String yLabel, int nAxes,
double xmin,double xmax, double ymin, double ymax) {
this(title,xLabel,yLabel,nAxes,xmin,xmax,ymin,ymax,1,"dot");
}
public Plot(int nAxes,
double xmin,double xmax, double ymin, double ymax) {
this("Plot","x","y",nAxes,xmin,xmax,ymin,ymax,1,"dot");
}
public void paint(Graphics g) {
g.drawImage(buffer,0,0,this); // draw image onto screen
}
private void setScale() {
if(xmax > xmin)
scalex = (size().width-2*mg)/(xmax-xmin);
else {
System.out.println("Error xmax not greater than xmin");
return;
}
if(ymax > ymin)
scaley = (size().height-2*mg)/(ymax-ymin);
else {
System.out.println("Error ymax not greater than ymin");
return;
}
}
public void setAxes() {
int mg = 30;
int ix,iy;
if(xSize != size().width || ySize != size().height) {
xSize = size().width;
ySize = size().height;
setScale();
}
b.clearRect(0,0,getSize().width,getSize().height);
switch (nAxes) { // draw axes and axis labels
case 1: b.drawLine(mg,size().height-mg,size().width-mg,size().height-mg);
b.drawString(xLabel,size().width/2,size().height-10);
break;
case 2: b.drawLine(mg,size().height-mg,mg,mg);
b.drawLine(mg,size().height-mg,size().width-mg,size().height-mg);
b.drawString(xLabel,size().width-2*mg,size().height-10);
b.drawString(yLabel,10,20);
break;
case 3: b.drawLine(mg,size().height-mg,size().width-mg,size().height-mg);
b.drawLine(size().width/2,size().height-mg,size().width/2,mg);
b.drawString(xLabel,size().width-2*mg,size().height-10);
b.drawString(yLabel,size().width/2,20);
break;
case 4: b.drawLine(mg,size().height/2,size().width-mg,size().height/2);
b.drawLine(size().width/2,size().height-mg,size().width/2,mg);
b.drawString(xLabel,size().width-2*mg,size().height/2+20);
b.drawString(yLabel,size().width/2,20);
break;
case 5: b.drawLine(mg,size().height/2,size().width-mg,size().height/2);
b.drawLine(mg,mg,mg,size().height-mg);
b.drawString(xLabel,size().width-2*mg,size().height/2+20);
b.drawString(yLabel,mg,20);
break;
}
repaint();
}
public void clearPoints() {
repaint();
}
public void plotPoints(double x[],double y[]) {
int ix,iy;
for(int i = 0; i < x.length; i++) { // plot points
ix = (int)((x[i]-xmin)*scalex) +mg;
iy = size().height - (int)((y[i]-ymin)*scaley) - mg;
if(symbolSize > 1) {
if(symbolType == "fillsquare")
b.fillRect(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
else if(symbolType == "opensquare")
b.drawRect(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
else if(symbolType == "opencircle")
b.drawOval(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
else
b.fillOval(ix-symbolSize/2,iy-symbolSize/2,symbolSize,symbolSize);
}
else
b.drawLine(ix,iy,ix,iy);
}
repaint();
}
}
package simphy;
/* Creates Frame for drawing on using world coordinates. y increases as you move up,
x increases as you move right. Unless otherwise specified methods use world
coordinates. */
import java.awt.*;
public class WorldGraphics extends Frame {
double scalex,scaley,xmin,ymin,xmax,ymax;
Image buffer;
Graphics b;
Color c = Color.black;
boolean toScreen = true; // draw to screen as well as buffer
public WorldGraphics(String title,
double xmin,double xmax, double ymin, double ymax) {
this.xmin = xmin;
this.ymin = ymin;
this.xmax = xmax;
this.ymax = ymax;
double f = (ymax-ymin)/(xmax-xmin);
setTitle(title);
setSize(360,(int)(360*f));
setScale();
setLocation(250,170);
setVisible(true);
buffer = createImage(getSize().width,getSize().height);
b = buffer.getGraphics();
}
public void setScale() {
if(xmax > xmin) {
scalex = (getSize().width)/(xmax-xmin);
}
else {
System.out.println("Error xmax not greater than xmin");
return;
}
if(ymax > ymin) {
scaley = (getSize().height)/(ymax-ymin);
}
else {
System.out.println("Error ymax not greater than ymin");
return;
}
}
private int scrX(double x) {
return (int)((x-xmin)*scalex);
}
private int scrY(double y) {
return getSize().height - (int)((y-ymin)*scaley);
}
private int scrDX(double dx) {
return (int)(dx*scalex);
}
private int scrDY(double dy) {
return (int)(dy*scaley);
}
public void setToScreen(boolean toScreen) {
this.toScreen = toScreen;
}
public void drawLine(double x1, double y1, double x2, double y2) {
b.drawLine(scrX(x1),scrY(y1),scrX(x2),scrY(y2));
if (toScreen) repaint();
}
public void fillRect(double x, double y, double dx, double dy) {
b.fillRect(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
if (toScreen) repaint();
}
public void drawRect(double x, double y, double dx, double dy) {
b.drawRect(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
if (toScreen) repaint();
}
public void drawRect(int x, int y, int dx, int dy) { // uses screen coordinates
b.drawRect(x,y,dx,dy);
if (toScreen) repaint();
}
public void fillRect(int x, int y, int dx, int dy) { // uses screen coordinates
b.fillRect(x,y,dx,dy);
if (toScreen) repaint();
}
public void fillOval(double x, double y, double dx, double dy) {
b.fillOval(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
if (toScreen) repaint();
}
public void drawOval(double x, double y, double dx, double dy) {
b.drawOval(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
if (toScreen) repaint();
}
public void drawCircle(double x, double y, double r) {
b.drawOval(scrX(x)-scrDX(r),scrY(y)-scrDY(r),scrDX(2*r),scrDY(2*r));
if (toScreen) repaint();
}
public void fillCircle(double x, double y, double r) {
b.fillOval(scrX(x)-scrDX(r),scrY(y)-scrDY(r),scrDX(2*r),scrDY(2*r));
if (toScreen) repaint();
}
public void clearRect(double x, double y, double dx, double dy) {
b.clearRect(scrX(x),scrY(y)-scrDY(dy),scrDX(dx),scrDY(dy));
if (toScreen) repaint();
}
public void clearBuffer() {
b.clearRect(scrX(xmin),scrY(ymin)-scrDY(ymax-ymin),scrDX(xmax-xmin),scrDY(ymax-ymin));
}
public void clearLine(double x1, double y1, double x2, double y2) { // erase line
Color cSave = c;
b.setColor(getBackground());
drawLine(x1,y1,x2,y2);
b.setColor(cSave);
}
public void drawString(String s, double x, double y) {
b.drawString(s, scrX(x),scrY(y));
if (toScreen) repaint();
}
public void drawString(String s, int x, int y) { //uses screen coordinates
b.drawString(s,x,y);
if (toScreen) repaint();
}
public void setColor(String s) {
if(s == "red") c = Color.red;
else if(s == "blue") c = Color.blue;
else if(s == "black") c = Color.black;
else if(s == "green") c = Color.green;
else if(s == "yellow") c = Color.yellow;
else if(s == "white") c = Color.white;
else if(s == "magenta") c = Color.magenta;
else if(s == "cyan") c = Color.cyan;
else if(s == "orange") c = Color.orange;
else if(s == "pink") c = Color.pink;
else if(s == "random") c = new Color((int) (Math.random()*255),
(int) (Math.random()*255), (int) (Math.random()*255));
b.setColor(c);
}
public void drawBuffer() {
Graphics g = getGraphics();
g.drawImage(buffer,0,0,this); // draw image onto screen, useful for animation
}
public void paint(Graphics g) {
g.drawImage(buffer,0,0,this); // draw image onto screen
}
}
Summary of some Basic Java Syntax
ClassName objectName = new ClassName();
ClassName objectName;
objectName = new ClassName();
double xarray = new double[10];
double 2dxarray = new double[10][20];
double xarray[];
xarray = new double[20];
double xarray[] = {1,2,3,4,5};
ClassName.staticMethodName();
objectName.methodName();
ClassName.staticVariableName;
objectName.variableName;
for(int i = 0; i < n; i++) {
}
while(i < n) {
}
if(a == b) { // equals
}
if(a != b) { // not equals
}
else if (c == d) {
}
else {
}
switch(n) {
case 0:x = 5;y = 7;break;
case 1:x = 15;break;
case 2:x = 3;y = 9;break;
case 3:x = 25;break;
default: x = 100;
}