This section describes a fictitious on-line course module for understanding the relationship between equations and their graphical representation. This example puts in practice much of the techexplorer Core Java API as well as leverages many of the connections between executable content in a web page.
Before we discuss the details of this example,
invoke the Java GraphIT application
to get an overall idea of the layout and workings of the interactive Java applets.
In particular notice that when you click on the trig expression display or click/drag on
the slider with the mouse, both the
trig expression display and the graph above it are updated.
To best understand the discussion of this example, the reader should have some understanding of how to implement Java GUI components, know a little about JavaScript, know how to create techexplorer content that can be scripted by both Netscape and Internet Explorer using the <EMBED> and <OBJECT> tags, and understand the Java 1.1 event handling model. It may also help the reader to have copies of the Java source code for the GraphIT and GraphITControl applets for referral while studying this document. The HTML source for the example may also be helpful. The latter can be obtained by going to the GraphIT example web page by pressing the techexplorer example button above and then using the facility of your browser that displays the HTML source code for the page being rendered by the browser.
We begin our explanation of the implementation of this example by focusing on the several components of the GraphIT module: the LaTeX material for the course module, the GraphIT applet, the GraphITControl applet, and the techexplorer trig expression display area. First, let us look at a diagram that shows the overall layout of the browser window.
Standard HTML display of title and Logo | |
(1) techexplorer display of introductory mathematical text | |
(2) techexplorer display of three paragraphs of mathematical text | (3) Java Applet GraphIT |
(4) techexplorer display of mathematical expressions for trig functions to be graphed | |
(5) Java Applet GraphITControl | |
Standard HTML display of navigation buttons and trademark info |
Three of the regions, denoted (1), (2), and (4), in the diagram above contain techexplorer displays. The first two are used for formatting the LaTeX text that describes the module. The GraphIT applet, denoted (3) above, plots the trig curves and is controlled remotely by the GraphITControl applet, denoted as (5). The GraphITControl applet displays a slider and provides our first examples of inter-applet communication and techexplorer event listeners using the techexplorer event listener interface. The third techexplorer display region, denoted (4) above, is used to dynamically render the mathematical expressions for the trig functions as they change. It is also the object that fires the techexplorer events for which the GraphITControl applet listens.
The key new ideas in this example are (a) the communication that is needed between the GraphIT applet and the GraphITControl applet (that is, inter-applet communication), (b) the communication that is needed between the GraphITControl applet and the techexplorer trig function display, and (c) the use of the Java interfaces in the techexplorer event listener classes that are needed to implement (b). Consequently, our discussion will concentrate on these three topics.
At this point the reader should clearly fix in his/her mind exactly which component
is referred to by each of the three labels: the GraphIT applet, the GraphITControl
applet, and the techexplorer trig function display. To do this, refer
again, if necessary, to the diagram above (they are components denoted (3), (5), and (4)
respectively in the diagram) and/or to the full-blown display.
The GraphIT applet plots the trig curves.
There are, however, two methods in the GraphIT applet that are crucial to the communication between the GraphIT and GraphITControl applets so we need to highlight them. They are setParam() and setCurve(). The GraphIT applet graphs either a cos( nx ) or a sin( nx ) function. The n in these functions is a parameter that can be changed by clicking/dragging the slider so setParam() is used by the GraphITControl applet to update this parameter.
Clicking on the trig function display can change the function being graphed from a cos function to a sin function, or vice versa. The setCurve() method is used by the GraphITControl applet to tell the GraphIT applet about these changes. The code looks like this:
import java.awt.*; import java.applet.Applet; public class GraphIT extends Applet { ... public void setParam( int p ) { trigCurve.setParam( p ); } public void setCurve( int curveID ) { trigCurve.setCurve( curveID ); } }The GraphITControl applet uses its updateAll() method to update the graph area in response to the user clicking on the techexplorer display for the trig functions or to clicking/dragging the mouse on the slider. It calls the setParam() and setCurve() methods and then invokes repaint(), using its handle to GraphIT, to redraw the graph. This is discussed in more detail in the section below on the GraphITControl applet.
The GraphIT applet implements the following Java classes:
Class | Description |
GraphIT | Remotely controlled graphing applet. |
TrigCurve | Implements an object representing a sin or cos curve. |
techexplorer trig function display is used to indicate the current
equation that is being plotted
by the GraphIT applet. techexplorer sends
events to the GraphITControl applet.
These events are used to toggle between the two trig equations. The equation currently being
graphed is displayed in red.
The following HTML embeds the techexplorer trig function display area in a browser window. Here the web browser object name for the ActiveX control instance of techexplorer is "TrigExprControl" while that for the Netscape plugin is "TrigExprPlugin." These names are used by the JavaScript code in the begin() method to send a handle for the techexplorer instance to the GraphITControl applet.
<OBJECT NAME="TrigExprControl" CLASSID="clsid:5AFAB315-AD87-11D3-98BB-002035EFB1A4" WIDTH=292 HEIGHT=100> <PARAM NAME="DataType" VALUE="0"> <PARAM NAME="Data" VALUE="\pagecolor{lightgray}\colorbox{white} {Select:\makebox[1.6in][r]{\color{black} \begin{eqnarray} \color{red} y & \color{red}= & \color{red}\sin(10x)\\ y & = & \cos(x) \end{eqnarray}}}"> <EMBED NAME="TrigExprPlugin" TYPE="application/x-techexplorer" TEXDATA="\pagecolor{lightgray}\colorbox{white} {Select:\makebox[1.6in][r]{\color{black} \begin{eqnarray} \color{red}y & \color{red}= & \color{red}\sin(10x)\\ y & = & \cos(x) \end{eqnarray}}}" WIDTH=292 HEIGHT=100 > </EMBED> </OBJECT>The above code is found in the JavaScript method displayTexWithName(). For more information on the HTML code needed to create techexplorer content that can be scripted by both Netscape and Internet Explorer, see Creating techexplorer Documents.
The techexplorer event listener interface is used by the GraphITControl applet to implement the event handlers for the events generated by the techexplorer trig function display. So this section gives a general overview of these facilities.
The techexplorer event listener interface provides for the one-to-many dependency between techexplorer and appropriately registered Java event handler objects. A techexplorer listener can be an instance of any Java class that implements the relevant methods in one or more of the techexplorer listener interfaces:
When a techexplorer display receives an event such as the user clicking the mouse over the display area, all the Java objects that are registered to listen to that particular event are notified through a call to an interface method. A Java object can register as an event handler by using one of the corresponding ibm.techexplorer.techexplorer event listener registration methods:
public void addFocusListener( FocusListener listener )
,public void addInstanceListener( InstanceListener listener )
,public void addKeyListener( KeyListener listener )
,public void addMouseListener( MouseListener listener )
,public void addMouseMotionListener( MouseMotionListener listener )
, andpublic void addtechexplorerListener( techexplorerListener listener )
.For future reference, we point out that the two Java classes ibm.techexplorer.plugin.techexplorerPlugin and ibm.techexplorer.control.techexplorerControl are derived from the ibm.techexplorer.techexplorer for the techexplorer plugin and ActiveX control respectively.
The relationship between techexplorer and Java classes that implement a techexplorer listener interface are based on the Observer/Subject paradigm used by the Java 1.1 event model. However, Java 1.1 is not needed in order to use the techexplorer listener mechanism. More information regarding the techexplorer event listener mechanism can be found in the AWTEvent annotated reference.
To prevent dangling references to techexplorer event listeners, the techexplorerPlugin reflection class provides these listener removal methods
public boolean removeFocusListener( FocusListener listener )
,public boolean removeInstanceListener( InstanceListener listener )
,public boolean removeKeyListener( KeyListener listener )
,public boolean removeMouseListener( MouseListener listener )
,public boolean removeMouseMotionListener( MouseMotionListener listener )
, andpublic boolean removetechexplorerListener( techexplorerListener listener )
.Be sure to call these methods when event notification is no longer needed or a Java object is to be destroyed. The InstanceListener interface defines the methods that a Java object must implement to receive notifications that techexplorer is shutting down. These methods can be used by techexplorer listeners to guard against dangling references to a techexplorerPlugin reflection instance.
Current Restriction: In this release, techexplorer Java objects can only listen to events that affect the whole document. However, the ibm.techexplorer.awt.event.MouseEvent has been augmented to provide programmatic access to the Document Object Model tree representation of the document.
Since the Slider class is a fairly straightforward Java GUI component implementation, we do not discuss it further except to note that it uses the Java 1.0 event handling model (to enable usage by many browsers) for responding to mouse clicks or dragging by the mouse. This is a different model from the one used by the techexplorer that is based on the new Java event handling model introduced in Java 1.1. The two different models, both used in the GraphITControl implementation, could be confusing to the reader if not clearly distinguished. For more information on writing Java GUI classes like the Slider class, see the general Java references given above. For more information about the Java 1.1 model for events and event handling, see the Lesson: Writing Event Handlers from The Java Tutorial. For more information about the Java 1.0, see the first edition of Horstmann and Cornell, Core Java published by Prentice-Hall. See the Slider class in the complete listing of the GraphITControl code for the details of the implementation of this component.
<APPLET NAME="GraphIT" ARCHIVE="NpExamples.jar" CODE="GraphIT.class" CODEBASE="Java" WIDTH=292 HEIGHT=300> <PARAM NAME="cabbase" VALUE="AxExamples.cab"> </APPLET>
There is one complication, however. getApplet() cannot return a reference to the GraphIT applet until the GraphIT applet is loaded (if the applet is not loaded, the method returns null), but the loading/initialization of the GraphIT and GraphITControl applets is done asynchronously. Thus, to insure that getApplet() eventually returns a non-null value, it is embedded in a loop that waits for a non-null value to be returned as is seen below.
Applet graphITHandle = null; ... public void start() { do { try { Thread.sleep(50); // Give other threads a chance to run, esp the thread } // loading/initializing the GraphIT applet catch (InterruptedException e) { }; graphITHandle = getAppletContext().getApplet("GraphIT"); } while(graphITHandle == null); }Once a handle is obtained, the public methods of the GraphIT applet can be invoked to update the graph.
For more information about inter-applet communication, see the section "The Applet Context" in the chapter on Applets in Horstmann and Cornell, volume I .
Rather than the applet invoking a method to obtain a handle to the techexplorer display, which is an object created by the HTML page, the JavaScript begin() method from the HTML page passes the handle to the applet by invoking either the setPlugin() or the setControl() method of the GraphITControl applet. Here is the code for the begin() method; note the use of the names TrigExprPlugin and TrigExprControl discussed earlier.
function begin() { var app = document.applets["GraphITControl"]; if ( document.TrigExprPlugin ) app.setPlugin( document.TrigExprPlugin ); if ( document.TrigExprControl ) app.setControl( document.TrigExprControl ); }Both setPlugin() and setControl() initialize the texplorer instance variable with the handle passed by JavaScript and then register the applet as a listener for the display. The code for setPlugin() is given below; the code for setControl() is similar.
public void setPlugin( techexplorer obj ) // Called by the JavaScript code in the HTML { // page to provide a handle to the Netscape plugin. if ( obj instanceof techexplorer ) // The handle is used to register a listener texplorer = obj; // on the techexplorer component that displays // the formulae for the curves that are graphed // Register the event listener for the techexplorer trig function display texplorer.addMouseListener( (MouseListener)this ); }Now, let's look at GraphITControl's implementation of the MouseListener interface. Actually only one method is needed to respond to the mouse clicks, in this case, the mouseRelease() method. Its implementation decides which equation is being selected by the user in the techexplorer trig function display and then calls updateAll() to update the graph panel and the techexplorer trig function display. The other methods simply appear with empty bodies. Here is the code for implementing the interface.
public void mouseClicked( MouseEvent e ) { } public void mouseEntered( MouseEvent e ) { } public void mouseExited( MouseEvent e ) { } public void mousePressed( MouseEvent e ) { } public void mouseRelease( MouseEvent e ) { Dimension d = size(); // Get size of techexplorer display int y = e.getY(); // Get y coordinate of mouse click if (y < 3*d.height/5){ // Since y coordinate is at bottom of the cursor, a better curveID = TrigCurve.SINCURVE; // feel is obtained by letting y be a little more than } // 1/2. if ( y >= 4*d.height/5 ){ curveID = TrigCurve.COSCURVE; } updateAll( ); }
The updateAll() method, used above in the mouseRelease() method, updates both the techexplorer display and the graphing applet. First, it recalculates the appropriate LaTeX expression needed to update the techexplorer display and then calls the reloadFromTeXString() method from the ibm.techexplorer.techexplorer class to redisplay the trig functions. Then it sets the appropriate curve parameters and invokes GraphIT's repaint() method. Now for the code - the part that updates the techexplorer display is shown in red; the part that updates the GraphIT applet is shown in green.
public void updateAll( ) { int n = slider.getSliderLoc(); String nStr = ""; if (n != 1) nStr += n; // To avoid displaying 1x techexplorerDisp = "\\pagecolor{lightgray}\\colorbox{white}{Select:" + "\\makebox[1.5in][r]{\\color{black}"; if ( curveID == TrigCurve.SINCURVE ) { techexplorerDisp += "\\begin{eqnarray}" + "\\color{red}y & \\color{red}= & \\color{red}\\sin(" + nStr + "x)\\\\" + " y & = & \\cos(x)" + "\\end{eqnarray}}}"; } if ( curveID == TrigCurve.COSCURVE ) { techexplorerDisp += "\\begin{eqnarray}" + " y & = & \\sin(x)\\\\" + "\\color{red}y & \\color{red}= & \\color{red}\\cos(" + nStr + " x)\\\\" + "\\end{eqnarray}}}"; } // Wait, if necessary, until the HTML page has been loaded and texplorer // has been initialized. while(texplorer == null && !texplorer.isReady()) { try { Thread.sleep(50); } catch (InterruptedException e) { }; } texplorer.reloadFromTeXString( techexplorerDisp ); // Redisplay the panel ((GraphIT)graphITHandle).setParam( slider.getSliderLoc() ); // Update curve definition ((GraphIT)graphITHandle).setCurve( curveID ); // Set sin or cos curve to plot ((GraphIT)graphITHandle).repaint( ); // Regraph curve }
There is one more coordination issue with which our code must deal. The JavaScript begin() method is called when the HTML page finishes loading. However, the loading of the HTML page and the loading/initialization of the applets are done asynchronously, thus before the first use of the instance variable texplorer in the GraphITControl applet, we insert a wait loop to wait, if necessary, until begin() has done its job. This is the purpose of the code
// Wait, if necessary, until the HTML page has been loaded and texplorer has been initialized. while(texplorer == null && !texplorer.isReady()) { try { Thread.sleep(50); } catch (InterruptedException e) { }; }in the implementation of updateAll() displayed above. Normally, one likes to initialize all of an applet's instance variables in either the init() or start() methods of the applet. However, some browser implementations apparently do not consider an HTML page to be fully loaded until all the applets have been loaded and initialized, i.e., both init() and start() have completed. Thus, if we put the above loop in the init() or start() methods of the applet, the begin() that initializes the applets texplorer variable will never be called causing a deadlock. This is the reason the coordination loop is placed just before the first use of texplorer instead of one of the normal places for initializing an instance variable of an applet.
Finally, the code of the applet destroy() method removes this applet from the MouseListener event list.
For more information about obtaining cross web browser handles to the ibm.techexplorer.techexplorer instance revisit our discussion, of the Java Editor applet.
The GraphITControl applet implements the following Java classes:
Class | Description |
GraphITControl | Applet for updating the techexplorer display and GraphIT applet. |
Slider | Component for changing the curve parameters. |
Click here for the whole program. Note that since some browsers do not support Java 1.1, the GraphITControl applet is Java 1.0 compliant.
Note: This application could have been implemented using only one applet if the techexplorer expression display were placed below the slider. It was implemented using two applets in order to demonstrate inter-applet communication.