Now you already know how to get a reference (handle) to the browser. This is a necessary step in any situation. In the next subsections we will discuss how to do the following:
Those basic operations are illustrated in this figure.
For operations such as reading or sending information to a VRML node you first will need a reference to this node. In this subsection we will teach you first how to get a reference to a named node that exists in the VRML scene, a reference to its EventIn field we want to set and some elementary Java widget programming.
Let's look first at the following simple VRML scene. It will display a red ball. Now we want to be able to change its color with a few simple buttons from the Java applet.
DEF Ball Transform { children [ Shape { appearance Appearance { material DEF MAT Material { diffuseColor 0.8 0.2 0.2 } } geometry Sphere {} } ] }
In order to do so, we must first get a reference to the node which defines
the color, i.e. DEF MAT Material {...}
. Next, we need a reference
to the set_diffuseColor
field. Finally, we
we must be able to set a value to this EventIn field.
The following example just does this:
Contents: | getNode(), getEventIn() |
HTML page: | eai/rgb-change/rgb-change.html |
JAVA Code: | eai/rgb-change/RGBChange.java |
Directory: | (dir) |
Here is the relevant code in the Java applet for getting the node and field references:
browser.getNode("MAT")
method will get a reference to the material
node which we called ``MAT'' in the VRML scene.
material.getEventIn("set_diffuseColor")
method will do the same
for the eventIn field.
..... Node material = null; EventInSFColor diffuseColor = null; ...... public void init() { ........ // Get the material node... material = browser.getNode("MAT"); // Get the diffuseColor EventIn diffuseColor = (EventInSFColor) material.getEventIn("set_diffuseColor"); ....... }
Java Newbies need some more explanation (others can skip this):
The reference to the VRML browser is hold by a variable we called
``browser''. It has been initialized of type ``Browser''. Browser is
a class that defines the ``getNode'' method allowing to retrieve named
nodes from the VRML scene.
In a similar way we assigned the result of
browser.getNode("MAT")
to the material
variable we declared as
type Node. Let's just show you the definition of the ``Node'' class
from
the EAI Spec
(in Java code format):
public Node getNode(String name) throws InvalidNodeException;This means that getNode (a) wants as argument a node name (the string of a DEF), (b) returns an instance of a Node class (i.e. the reference to a node) unless it fails in which case it signals an InvalidNodeException. More later about this latter case.
Now the ``Node'' class defines a method called getEvent
that
will return an instance of the EventIn class. However
you must cast (i.e. translate) this instance
to the appropriate class you are interested in.
The reason is that getEventIn
can return different types of
values.
In our example we cast to
(EventInSFColor)
in the following line:
diffuseColor = (EventInSFColor) material.getEventIn("set_diffuseColor");You have to do this everytime you deal with some event fields. The EAI Spec is pretty self explaining about those types. So far, we only have the handles on VRML things we want to manipulate. In order to obtain what we want we now must proceed with some ordinary Java coding. If you look at the Java code and the applet you can see that we painted three simple buttons:
// paint 3 simple Java buttons add(new Button("Red")); add(new Button("Green")); add(new Button("Blue"));
The Applet class which is imported from java.applet.*
is a child of the java.awt.Component
class which defines a simple
action
event method.
This method is activated (i.e. called) with the Event and the Object
triggered when the user clicks on a button.
The programmer now has to deal with the event, i.e. implement an ``action'' method
for this applet.
Since the ``action'' method is depreciated in Java 1.1. we will not explain
much here, but revise the code once most Netscape and VRML plug-in
users will have versions that fully support Java 1.1.
Let's just look at the VRML related part for dealing with the Blue button:
float[] color = new float[3]; ....... public boolean action(Event event, Object what) { // handle Java user actions if (event.target instanceof Button) { Button b = (Button) event.target; .......... color[0] = 0.2f; color[1] = 0.2f; color[2] = 0.8f; diffuseColor.setValue(color); ...... } return true; }In the prologue code of the class (see just above) we did declare a ``color'' variable of type array that can take take three floating point elements. All we have to do after identifying which button has been clicked on is the following:
setValue()
method. This method
is defined by the EAI's EventInSFColor
class.
action()
method is called whenever the user does something
and the first lines of codes will identify events generated by
clicking on a button.
Let's summarize what you have learned:
Now let's make our Applet a bit more bullet proof.
The getNode
and getEventIn
method will throw exceptions
that we could handle, e.g. by giving some feedback to the user and disabling
Java code that depends on references not found:
Contents: | getNode(), getEventIn(), Java: try/catch |
HTML page: | eai/rgb-change/rgb-change-test.html |
JAVA Code: | eai/rgb-change/RGBChangeTest.java |
Directory: | (dir) |
The following code will implement what we do when references are not found. Java's ``try'' statement allows us to define ``catch'' clauses that are called by the Java interpreter when something is wrong. (Recall the definition of the the getNode discussed in the previous section 6.3.1).
try { // Get the material node... material = browser.getNode("MAT"); // Get the diffuseColor EventIn diffuseColor = (EventInSFColor) material.getEventIn("set_diffuseColor"); } catch (InvalidNodeException ne) { add(new TextField("Failed to get node:" + ne)); error = true; } catch (InvalidEventInException ee) { add(new TextField("Failed to get EventIn:" + ee)); error = true; }
add(new TextField("Failed to get node:" + ne));will paint a text field on the Java Applet with the error message we defined. (Note, that we could just have written something to the Java Console instead.) In addition, the catch statements will set the ``error'' variable to true. If true the action method will not try to handle any events, i.e. it will just exit. Below is the the code (in old Java 1.0.x style) that whill handle the event.
public boolean action(Event event, Object what) { if (error) { showStatus("Problems! Had an error during initialization"); return true; // Uh oh... } .......
Finally note the usage of the ``showStatus'' method which will print a message on the status bar (the bottom) of your WWW client window. If you now want to see how this works play with the following example which shows a Java Applet where ``MAT'' it misspelled as ``MATS'' in the code:
Contents: | getNode(), getEventIn(), Java: try/catch |
HTML page: | eai/rgb-change/rgb-change-err.html |
JAVA Code: | eai/rgb-change/RGBChangeErr.java |
Directory: | (dir) |
The next example deals with reading information from a VMRL scene. Note that this is not the same as receiving information (the equivalent of VRML's ROUTEing) which we shall introduce later.
The scenario of our next examples deals with a (very) simple ``where I am'' problem. The user can click on a button an it will tell him some information about the EntryView Point.
Contents: | getEventOut(), |
HTML page: | eai/get-node-info/get-node-info-s.html |
JAVA code: | eai/get-node-info/GetNodeInfoS.java |
Directory: | (dir) |
Retrieving Information from a VRML scene is very much the same as writing information,
something we learned in the previous section 6.3.1.
We also need a handle to an Event field. In this case we will read from
EventOut fields. Remember that: EventOut and not just the
field. Therefore ordinary VRML exposed fields can be accessed by something
like <handle>.getEventOut("<field_name>_changed")
as in the lines
below:
EventOutSFVec3f positionVP = null; EventOutSFRotation orientationVP = null; ...... positionVP = (EventOutSFVec3f) entryVP.getEventOut("position_changed"); orientationVP = (EventOutSFRotation) entryVP.getEventOut("orientation_changed");
Once we got the handle we can read. In the action method of our example we get the position and the orientation of a Viewpoint with the following lines of code:
currentPosition = positionVP.getValue(); currentOrientation = orientationVP.getValue();
Again some comments for Java newbies: The following defines a text widget to which we can print text:
TextArea output = null; ..... public void init() { ...... output = new TextArea(5, 40); add(output); ...... } public boolean action(Event event, Object what) { ....... output.appendText("Entry ViewPoint is at" + " x=" + currentPosition [0] + " y=" + currentPosition [1] + " z=" + currentPosition [2] + "\n"); ..... }Such a thing is definitively better than telling the user to open up the Java Console.
The next example does exactly the same, but includes error handling. Of new interest is only the ``InvalidEventOutException'':
public void initScene() { try { ....... positionVP = (EventOutSFVec3f) entryVP.getEventOut("position_changed"); orientationVP = (EventOutSFRotation) entryVP.getEventOut("orientation_changed"); } ......... catch (InvalidEventOutException ee) { System.out.println("InvalidEventOutException: " + ee); die("initScene: EventOut Field not found!"); return; } }Also note that that a ``die'' method has been defined that is called when encountering an error. This adds some better modularization to the code.
Finally you can look at a minimal implementation of the ``start'', ``stop'' and ``destroy'' methods that are called by the Java interpreter.
Contents: | getNode(), getEventOut(), Java: try/catch |
HTML page: | eai/get-node-info/get-node-info.html |
JAVA code: | eai/get-node-info/GetNodeInfo.java |
Directory: | (dir) |
In this subsection you will learn how to create a VRML scene from a string
and to replace the existing scene in the browser.
Let's start with an empty world, i.e. all there is in the *.wrl file
is a line that will
get the plug-in going:
#VRML V2.0 utf8
The following example will paint a blue ball as soon as the applet starts up:
Contents: | createVrmlFromString() |
HTML page: | eai/create/create-ex0.html |
JAVA code: | eai/create/CreateEx0.java |
Directory: | (dir) |
A Vrml scene (or tree) is represented in the Java Applet as as an array of Nodes which we will initialize as follows:
Node[] scene = null;
The Browser class' createVrmlFromString
method will take a simple
string containing ordinary VRML statements and then create an array of VRML
nodes from it. In this example we just add simple strings together, but
of course you also could produce strings from variables and methods to
program some more useful applet.
The code below will just create a few VRML objects.
scene = browser.createVrmlFromString( "DEF Camera Viewpoint {\n" + " position 0 0 5}\n" + "DEF MySphere Transform {\n" + " children [ \n" + ...... " ] \n" + " } \n" );
Once the scene array contains VRML nodes (represented as Java instances)
the rest is very simple.
We can replace the current (in this
case empty) VRML scene by the nodes in the new scene array
with the replaceWorld
method.
browser.replaceWorld(scene);Note that we also could have added these nodes to a children field of an existing scene without replacing everything else. With what you already learned you ought to be able to set a value to a ``addChildren'' field of a grouping node, but we will demonstrate it anyhow in section 6.3.5.
The next example is more complex, because it will separately create a series of VRML nodes and then assemble them together by setting respective EventIn fields. If you do not understand what it does you should read again the previous sections or just move on and come back later.
Contents: | createVrmlFromString() |
HTML page: | eai/create/create-ex.html |
JAVA code: | eai/create/CreateEx.java |
Directory: | (dir) |
A more sophisticated example from which the above has been inspired can be found in the EAI specification. A local copy is below. You can study it yourself :)
Contents: | createVrmlFromString() |
HTML page: | eai/create-test/create-test.html |
JAVA code: | eai/create-test/CreateTest.java |
Directory: | (dir) |
In this subsection we pull together most of what we have learned so far.
This applet will allow the user to add a (VrmlFromString created) ball
to an exiting Group node and also to remove it. The Vrml we originally start
with is very simple:
#VRML V2.0 utf8 DEF Camera Viewpoint { position 0 0 7 } DEF ROOT Group {}
addChildren
and the EventOut removeChildren
allowing you to add and remove objects from children.
We will make use of this feature in the next example.
Contents: | |
HTML page: | eai/add-remove/add-remove1.html |
JAVA code: | eai/add-remove/AddRemove.java |
Directory: | (dir) |
If you understood the previous subsections there is not much explaining needed.
Look first at these lines in the init()
method:
// Get root node of the scene root = browser.getNode("ROOT"); // Instantiate (get handle to) the EventIn objects addChildren = (EventInMFNode) root.getEventIn("addChildren"); removeChildren = (EventInMFNode) root.getEventIn("removeChildren");Note that
root.getEventIn("addChildren")
and
root.getEventIn("removeChildren")
produce EventInMFNode
s.
In the action()
method we then simply setValue()
the
node we want to remove or to add. Note that shape is an array that
holds the result of the createVrmlFromString()
operation.
if (b == addButton) { addChildren.setValue(shape); } else if (b == removeButton) { removeChildren.setValue(shape); }
This example is just a simplified version of the one found in the EAI spec. The original adds some error checking and feedback and you can look at it in the example below. Also, if the example above won't work on your browser, the one below will print out the reasons for you :)
Contents: | |
HTML page: | eai/add-remove-test/AddRemoveTest.html |
JAVA code: | eai/add-remove-test/AddRemoveTest.java |
Directory: | (dir) |
The last element we consider basic and essential in the EAI Spec is receiving Events from the Scene which as bit analogous to the ROUTE statement used with animated VRML and scripting. It is not the same as reading something from a scene which was discussed for example in subsection 6.3.3.
In the example we will discuss a simple TouchSensor example. When the user clicks on the cube it will change color (something that usually would not need the EAI).
Contents: | EventOutObserver |
HTML page: | eai/monitor-test/monitor-touch.html |
JAVA code: | eai/monitor-test/MonitorTouch.java |
Directory: | (dir) |
So what's new ?
Our applet
in order to receive call-backs from the VRML scene needs to
implement an
EventOutObserver
Interface. It can be done like this:
public class MonitorTouch extends Applet implements EventOutObserverOf course you also could define a subclass implementing
EventOutObserver
but it would be slightly more complicated.
In any case,
you must write a callback
method for the EventOutObserver
class in order to process events.
This method takes three arguments: the EventOut, the time and some
user definable data. Let's look at the code:
public void callback(EventOut who, double when, Object which) { // retrieve the state of isActive (see above the advise function) EventOutSFBool state = (EventOutSFBool) which; // only deal with the event if isActive was true, else the ball would flip back if (state.getValue() == true) { System.out.println("callback(): EventOut=" + who + " state =" + state.getValue()); // Change the color and remember it if (colorState == 1) { diffuseColor.setValue(redColor); colorState = 0; } else { diffuseColor.setValue(greenColor); colorState = 1; } } }
isActive
, i.e.
an EventOutSFBool
object related to the TouchSensor.
To set up the call-back we had to add the following lines
to the init()
method:
.... // Get the Touch Sensor Node sensor = browser.getNode("TOUCH"); // Get its touchTime EventOut isActive = (EventOutSFBool) sensor.getEventOut("isActive"); // Set up the callback isActive.advise(this, isActive); ....As you can see, EventOuts do have an advise method that is used to tell (advise) the class, that this EventOut will be used for a call-back. Let's go back to the
callback()
method listed above.
If you remember how to deal with state and
isActive Events from a TouchSensor
(see section 5.3.2 on page )
you know that isActive will both generate true and false events
depending on whether the user clicks or releases a mouse button.
Here again, we are just interesting in the ``down'' click:
EventOutSFBool state = (EventOutSFBool) which; // only deal with the event if isActive was true ... if (state.getValue() == true) { .... }The rest is fairly easy. If the ball is green (remembered within our Java code as
colorState
) we paint it red, else green.
The following line should be meaningful to you, else go back
to subsection 6.3.1.
diffuseColor.setValue(redColor);Voila, that's it. We have written an invisible applet that does something we have been doing before with Javascript (or that could be done with the Java Script node).
The following example will monitor the output of a TimeSensor Node and the rotation field of a spinning cube.
Contents: | EventOutObserver |
HTML page: | eai/monitor-test/monitor-test2.html |
JAVA code: | eai/monitor-test/MonitorTest2.java |
Directory: | (dir) |
The VRML scene we are dealing with is slightly more complex than the previous ones. In case you forgot all your basic animated VRML you can go back reading section 5.2.1 on . It just links the pulse of a TimeSensor to an OrientationInterpolator which sets the rotation field of a Transform node containing a cube.
On the Java Side there is not much more than in the previous example. Note that the advise methods simply passes an Integer as a way to identify the Event we have to handle. There are also 2 buttons to stop and start the animation, some error handling code, and a long loop that makes sure that we really get the browser. [I have a feeling that one should put the EAI/Java inits into the start() method to be sure that the VRML scene has enough time to fully load ... to be tested].
Finally you can now look at the RGB Test Applet from the EAI Spec. It does about everything you have learned so far.
Contents: | getEventIn, getEventOut, EventOutObserver |
HTML page: | eai/rgb/RGB-demo.html |
JAVA code: | eai/rgb/RGBTest.java |
Directory: | (dir) |
In the next sections we will discuss some slightly more complex examples and introduce some more EAI stuff.