[ prev | main | next ]

Graph Applet 3

This applet that draws the graph of a function and marks
a point on the graph with a pair of lines. It's a minor
variation on GraphApplet2, but the programming is
different. In this version, I don't use WcmPanel's to build the
applet, so I have to do more setup myself. In this version, I mark
the point on the graph differently:

The following source code is commented only where it differs
from GraphApplet2.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;

import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.JLabel;

import net.sourceforge.webcompmath.awt.ComputeButton;
import net.sourceforge.webcompmath.awt.Controller;
import net.sourceforge.webcompmath.awt.ExpressionInput;
import net.sourceforge.webcompmath.awt.Tie;
import net.sourceforge.webcompmath.awt.VariableInput;
import net.sourceforge.webcompmath.awt.VariableSlider;
import net.sourceforge.webcompmath.data.Constant;
import net.sourceforge.webcompmath.data.Function;
import net.sourceforge.webcompmath.data.Parser;
import net.sourceforge.webcompmath.data.Value;
import net.sourceforge.webcompmath.data.ValueMath;
import net.sourceforge.webcompmath.data.Variable;
import net.sourceforge.webcompmath.draw.CoordinateRect;
import net.sourceforge.webcompmath.draw.DisplayCanvas;
import net.sourceforge.webcompmath.draw.DrawBorder;
import net.sourceforge.webcompmath.draw.DrawGeometric;
import net.sourceforge.webcompmath.draw.DrawString;
import net.sourceforge.webcompmath.draw.Graph1D;
import net.sourceforge.webcompmath.draw.LimitControlPanel;
import net.sourceforge.webcompmath.draw.Panner;
import net.sourceforge.webcompmath.draw.WcmAxes;

* This applet is an example of how to use WCM to build a math applet
public class GraphApplet3 extends JApplet {

private static final long serialVersionUID = -2457479476633793064L;

private DisplayCanvas canvas;

* This overrides init() in JApplet
* @see java.applet.Applet#init()
public void init() {

Parser parser = new Parser();
Variable x = new Variable("x");

canvas = new DisplayCanvas();
canvas.add(new Panner());

CoordinateRect coords = canvas.getCoordinateRect();

LimitControlPanel limits = new LimitControlPanel(
LimitControlPanel.SET_LIMITS | LimitControlPanel.RESTORE, false);

ExpressionInput input = new ExpressionInput("sin(x)+2*cos(3*x)", parser);
Function func = input.getFunction(x);

Graph1D graph = new Graph1D(func);

VariableInput xInput = new VariableInput();
VariableSlider xSlider = new VariableSlider(coords
.getValueObject(CoordinateRect.XMIN), coords

Value yValue = new ValueMath(func, xSlider);
* A Value object to represent the y-coord of the point.

* Instead of using a crosshair to mark a point on the graph, it is
* marked with two gray lines and a small magenta oval. These geometric
* objects are represented as objects belonging to the class
* DrawGeometric, which makes it possible to draw a variety of geometric
* figures on a DisplayCanvas.
DrawGeometric vLine = new DrawGeometric(DrawGeometric.LINE_ABSOLUTE,
xSlider, new Constant(0), xSlider, yValue);
DrawGeometric hLine = new DrawGeometric(DrawGeometric.LINE_ABSOLUTE,
new Constant(0), yValue, xSlider, yValue);
DrawGeometric point = new DrawGeometric(DrawGeometric.OVAL_CENTERED,
xSlider, yValue, 3, 3);

DrawString info = new DrawString("x = #\nf(x) = #",
DrawString.TOP_LEFT, new Value[] { xSlider, yValue });
info.setFont(new Font("SansSerif", Font.BOLD, 12));
info.setColor(new Color(0, 100, 0));

ComputeButton graphIt = new ComputeButton("Graph It!");

setLayout(new BorderLayout(3, 3));

* In this version of the applet, I have built the interface from
* regular JPanels instead of WcmPanels. This puts responsibility for a
* lot more setup in the hands of the programmer. The gain is in
* efficiency. Here, my object is to avoid recomputing the graph just
* because the user adjusts the slider. To do this, I have to use two
* controllers, which listen for different user actions. (Of course,
* computers are so fast now that the extra computation probably doesn't
* add a perceptible delay. In this case, the extra design work is
* probably not worth the trouble.)
JPanel top = new JPanel();
top.setLayout(new BorderLayout(3, 3));
JPanel bottom = new JPanel();
bottom.setLayout(new BorderLayout(3, 3));
add(canvas, BorderLayout.CENTER);
// Add components directly to the applet.
add(limits, BorderLayout.EAST);
add(bottom, BorderLayout.SOUTH);
add(top, BorderLayout.NORTH);

top.add(input, BorderLayout.CENTER);
top.add(new JLabel(" f(x) = "), BorderLayout.WEST);
top.add(graphIt, BorderLayout.EAST);

bottom.add(xSlider, BorderLayout.CENTER);
bottom.add(xInput, BorderLayout.EAST);
bottom.add(new JLabel(" x = "), BorderLayout.WEST);

canvas.add(new WcmAxes());
canvas.add(new DrawBorder(Color.darkGray, 2));

Controller cc = new Controller();
* This controller will listen for changes in the VariableSlider or
* VariableInput, as well as in the limits on the coordinates.
xInput.setOnUserAction(cc); //
xSlider.setOnUserAction(cc); //

cc.add(new Tie(xSlider, xInput));
* Ties the values of the slider and VariableInput.

* I have to tell the controller which objects need to be recomputed
* when it sees some kind of change. This includes all the objects that
* depend on the x-coordinate. Note that this also includes xInput and
* xSlider, which need to be checked for changes in their values. The
* value associated with a VariableSlider or VariableInput doesn't
* actually change until a Controller checks it. (All this is the part
* of the setup that is done automatically when you build your interface
* from WcmPanels.)

Controller gc = new Controller();
* This controller will listen for changes in the function definition.

* I have to add the ExpressionInput to a Controller, since the function
* doesn't actually change unless the ExpressionInput is checked by a
* Controller. The graph needs to be recomputed when the function
* changes. You can add one Controller to another. Here, gc will call on
* cc to do all its checks and computations, in addition to. recomputing
* the graph.

* Set error reporters for the Controller. This error reporter is also
* used by cc, which has been added as a subcontroller to gc. So, it's
* not necessary to set a separate error reporter for cc

// Error reporter for the LimitControlPanel.

} // end init()

} // end class GraphApplet3

[ prev | main | next ]