PXLab Manual

[Home]    [Content]    [Previous Chapter]    [Next Chapter]


The PXLab Software API

PXLab Software Development System Installation

If you want to develop your own Java programs using the PXLab APIs or if you want to extend PXLab classes by creating your own stimulus objects then you need to download the PXLab source archive PXLabSrc.zip from the PXLab download area. For Windows users we suggest that they install the zip archive into a directory named jpxl in the root of drive C: because that is how the build file is defined. Following this will make it easier to adapt the system to your needs. The source path will be c:/jpxl/src in this case. However, the source tree may of course be installed into any arbitrary directory. The build file has to be adapted accordingly.

The PXLab source archive will install two directories:

images
contains various bitmap files.
src>
contains the Java source tree. The scr directory contains the build file named build.xml and two subdirectories: share and win32. The share subdirectory contains all shared sources and the win32 subdirectory contains the Windows native DLL sources for the library pxlab.dll.

Software Needed

PXLab needs some software packages for compilation. All of these are free or open source software packages.

The Java Development Kit

In order to compile the PXLab sources you have to download and install the latest Java Development Kit from Sun's download page. We do not follow the suggestion of the JDK installer to install the JDK into the 'Program files' directory but install the JDK into a subdirectory named jdk of a directory named javasoft on drive C:. This is for convenience and is not a necessity. Sun has the habit of creating a new name for every release of the JDK and so it would be neccessary to change the build file for every new release of the JDK. Always using jdk makes it easier to upgrade.

A Build Tool: Apache Ant

The PXLab source tree uses Apache Ant for compilation. Thus you should install Apache Ant to compile PXLab. We install Apache Ant into a subdirectory named ant of our javasoft directory. To get this we extract the Ant archive into directory javasoft and rename the resulting release dependent directory name to ant.

A Parser Generator: JavaCC

The PXLab design file grammar is defined by a JavaCC parser generator grammar file. Modification of the design file grammar or a recreation of the parser thus requires that the JavaCC parser generator is being installed. We download the archive and extract it into a subdirectory named javacc of the javasoft directory. This requires the same renaming procedure as we did with Ant, since JavaCC also carries its release number in the target directory.

The Serial Communications API Package

PXLab supports external devices connected to the serial port. The serial port software is not part of the JDK since the software support for the serial devices is hardware dependent. Using the serial communication port requires the installation of the Java Communications API for the respective machine and OS. The download package contains instructions how to install the package for various operating systems and Java development kit versions. For reasons unknown to me Sun does no longer support the Communications API for Windows. However, you may find the software using the link below.

For installation under Windows you have to do the following steps:

Note that at runtime this software is only required if external response buttons, external synchronization signals or other serial devices will to be used. Applets cannot use it.

The Java Media Framework

Playing movies with PXLab requires the Java Media Framework (JMF) package being installed. Be sure to follow the installation instructions of the JMF package carefully in order to make JMF work properly. It seems to be important that the order of installation is correct: First install the JDK, and then install the Java Media Framework. We install the JMF package into a subdirectory named jmf of the javasoft directory.

The Java SVG Toolkit: Batik

Images which are in the Scalable Vector Graphics (SVG) format can be shown with the Apache Java SVG toolkit Batik. The Batik toolkit has to be installed in order to compile the SVG support for PXLab. You may download the software from the Batik download page. PXLab uses only a subset of the Batik package. This subset is contained in a jar file named batik.jar which you will find in subdirectory src/share/ext of the PXLab source archive. Move this file into the same location (jdk/jre/lib/ext) as described earlier for the file comm.jar.

Building PXLab

Before starting the build under Windows you have to set some environment variables for the JDK, Ant, and JavaCC. There is a batch file named setup4pxlab.bat contained in directory jpxl/src/bin which can do this for you. You may run this batch in a Windows command window or you may use this batch file as a startup file for a Windows command window.

The PXLab build file 'build.xml' is located in the PXLab top level source directory jpxl/src. If you did not follow our installation instructions you may have to modify the build file according to your installation locations. If you use our installation suggestions then chances are high that the build file works unmodified. Open a command window, run the startup batch file, change into directory jpxl/src and type command 'ant'. This should build the complete PXLab package.

Implementation of new Display Objects

All display objects of PXLab are subclasses of the abstract class Display. Any concrete subclass has to define at least the following three methods:

  1. a constructor for instantiating subclass objects;
  2. the method create() to set up the lists of display and timing elements;
  3. the method computeGeometry() for computing the geometric properties of the display elements contained in the display.

These methods are abstract methods of class Display and must be defined concrete in any subclass.

In addition to these methods every Display object has to define additional experimental parameters which describe its properties.

Experimental Parameters

Displays are described by experimental color, geometry, and timing parameters which are declared as public ExPar objects. This can be done during class initialization using public initializers. Here is an example for a simple bar display:
    public ExPar Color = new ExPar(COLOR, 
	new ExParValue(PxlColor.gray), "Bar Color");

    public ExPar Width = new ExPar(HORSCREENSIZE, 
	new ExParValue(100), "Bar Width");

    public ExPar Height = new ExPar(VERSCREENSIZE, 
	new ExParValue(100), "Bar Height");

    public ExPar LocationX = new ExPar(HORSCREENPOS, 
	new ExParValue(0), "Horizontal Center Position");

    public ExPar LocationY = new ExPar(VERSCREENPOS, 
        new ExParValue(0), "Vertical Center Position");
This display uses five new experimental parameters. The first one is a color parameter and the other four are geometry parameters for width, height and location. The parameter types are given as arguments for the constructor. These type codes are only needed for interactive display editing purposes in order to provide most useful editing tools for the different types of parameters. The parameter type code is the first argument of the constructor ExPar(). The second argument is an initial value for each parameter and the third argument is a short label describing the parameter's purpose.

Every display object inherits several parameters from class Display. These mainly refer to timing and response properties such that many Display objects need not define their own timing parameters.

The Display Subclass Constructor

The constructor of a display is a simple and small method which does nothing but enter the display's name and content topic into PXLab's list of displays and thus makes it appear in one of the display selection sub-menus. The submenu where the display appears for selection corresponds to its content topic ID and is given as the second argument to the method which defines the title and the topic. Here is an example for the constructor of the class SimpleBar:

    public SimpleBar() {
	setTitleAndTopic("Simple Colored Bar", SIMPLE_GEOMETRY_DSP);
    }

The constructor calls the method setTitleAndTopic() of class Display with the display's menu entry and the menu topic code. Note that no geometric, no color, and no timing properties are defined by the constructor.

Instance Initialization

A Display object does nothing as long as it is not shown on the screen. It only appears for selection in one of the menus. When a Display object is selected, however, it has to be created and initialized. This is done by the method
    protected int create()
which is called by the Display manager after selection or by experimental runtime controllers when an experiment is being prepared. The method create() does the following initializations:

Defining the Geometric Properties of a Display

The first step to create a display is to create the geometry of the display. A display's geometry is defined by a list of colored display elements which make up the display. The single elements are objects of type DisplayElement and are entered into the display's display element list by the method
    protected int enterDisplayElement(DisplayElement p, int[] timing_group)
which also returns the object's index in the display element list. It is not necessary to completely define every element's geometry during initialization since this will be done later. What needs to be done is to associate a color with every display element. Thus the constructor of most DisplayElement objects gets at least one parameter: the color parameter associated with this object.

The class DisplayElement is an abstract class which has several derived classes for different types of display elements. Here is a list of available display elements:

All of these are subclasses of DisplayElement and have constructors which do not define the geometric properties but only set the element's color parameter. The following methods are available for setting the location and size of DisplayElement objects:

Most of these display elements have further geometric properties which my be set during geometry recomputation. Look at the respective display element's description to find out about these methods.

In our example we have only a single display element which gets the color parameter as an argument:

	bar_idx = enterDisplayElement(new Bar(Color), group[0]);

The return value of the method enterDisplayElement() is the index of the display element in a display's list of elements. This index will be used later so we have to store it in a local variable.

Timing Groups of DisplayElement Objects

Some displays may be divided up into subgroups of display elements such that all members of a group always appear simultanously on the screen whereas the single groups may be displayed sequentially. Many real experimental displays will have display element grouping in order to exactly control the sequential timing of groups of display elements.

In order to tell the PXLab runtime system which display elements belong to the same timing group every DisplayElement object is assigned a timing group code when it is entered into the display element list of a Display object. There is a global constant integer array

   int[] group;

which contains proper timing codes and we simply use this array's elements as timing group pattern. Thus the first timing group is assigned the group pattern value group[0], the second timing group gets group[1] and so on.

In our example we have only a single display element and thus we have only a single timing group:

	bar_idx = enterDisplayElement(new Bar(this.Color), group[0]);

The timing properties of a timing group of display elements are defined by associating timing parameters with a display's list of timing groups. This is done by calling the method

   public int enterTiming(ExPar timing, ExPar duration, 
     ExPar responseSet, int refIndex, ExPar rtime, ExPar rcode);
This method tells the real time control system which type of timer is to be used for measuring the timing group's duration, the duration value, the possible response set, the number of the timing group to refer to, and the experimental parameters which accept the actual response time or duration and the stopping code of the time interval. Note that response time and stopping code are data parameters which contain data after the display has been run. The other parameters define the timing properties.

In our example we simply use the predefined experimental parameters of class Display in order to defined the timing properties and accept the response data:

   enterTiming(this.Timer, this.Duration, this.ResponseSet, 
      0, this.ResponseTime, this.ResponseCode)

Return Value

This is all that has to be done during initialization. The method create() returns the display element index which points to that display element which should be this display's active element when it first appears on a display editor. Here is the complete initialization method: of our simple example:

    private int bar_idx;

    protected int create() {
	bar_idx = enterDisplayElement(new Bar(this.Color), group[0]);
	defaultTiming(0);
	return(bar_idx);
    }

Note that the method enterTiming() has been replaced by defaultTiming(0) since we onyl use the default timing parameters.

Computing the Display's Geometry

After a display is initialized it can be shown on a display panel. This requires that the display's geometry is computed with respect to the display panel's size. This is done by the method
    protected void computeGeometry()
This method is called by the realtime display controller. Before calling the computeGeometry() method the display controller sets the fields width and height of the active Display object. Here is a simple example for computeGeometry():
    protected void computeGeometry() {
	DisplayElement bar = getDisplayElement(bar_idx);
	int w = Width.getInt();
	int h = Height.getInt();
	bar.setRect(LocationX.getInt() - w/2, LocationY.getInt() - h/2, w, h);
    }
The method getDisplayElement() retrieves a single DisplayElement object with the given index from a Display's list of display elements. In order to retrieve a certain element we use the expression
	getDisplayElement(bar_idx)
which gets us the DisplayElement object at index bar_idx in this display's list of display elements. The class DisplayElement uses the method setRect() to set a Bar's location and size. Thus
	bar.setRect(LocationX.getInt() - w/2, LocationY.getInt() - h/2, w, h);
sets this object's location and size from the parameter values LocationX, LocationY, Width, and Height.

While the method create() is called only once when the display is being initialized, the method computeGeometry() is always called immediately before the display object appears on the screen. It is also called whenever the size of the display window has changed or whenever one of the geometry parameters of the display has been changed by a display editor.

Computing Colors

Some displays have colors which depend on other colors in the display. An example is a smooth transition from one color to another color like it is used in a Mach band display. In this case the dependent colors have to be recomputed whenever the independent colors are changed. Dependent colors should not be selected by the user for adjustment, they should only be selected for displaying their coordinates or for moving them to the color clipboard of a display editor.

There are two ways for Display objects to handle dependent colors: The display may define experimental parameters for these colors and these parameters' values may be recomputed by the method computeColors() whenever any color of the display has been adjusted. In this case a dependent color may be selected as currently active color of a display editor. The second way how a Display object may handle dependent colors is to only create them when drawing is required. In this case it is not possible to select the dependent color in a display editor since there will be no geometry object in the display's display element list corresponding to this color. If the user clicks at the respective screen position she or he will get the underlying background object's color as a selection.

In general dependent colors and the corresponding display elements should be entered into the respective tables whenever display editor selection should be possible. This will be the case when the respective object has a sufficiently large area to be accessible to the mouse pointer. If the respective object is so small that it hardly is accessible to the mouse pointer, then it does not make sense to enter it as a selectible object. The latter case usually holds for single screen lines as they are used for smooth color transitions.

Here is an example for color computing from the display class AdditiveColorMixer. This class shows three overlapping squares for simulating additive color mixing. It defines three independent and four dependent color parameters.

    public ExPar Square1Color = new ExPar(COLOR, new ExParValue(PxlColor.red), 
                                "Color of the First Square");
    public ExPar Square2Color = new ExPar(COLOR, new ExParValue(PxlColor.green), 
                                "Color of the Second Square");
    public ExPar Square3Color = new ExPar(COLOR, new ExParValue(PxlColor.blue), 
                                "Color of the Third Square");
    public ExPar Dep1Color = new ExPar(DEPCOLOR, new ExParValue (PxlColor.black),
                          "First Dependent Color");  
    public ExPar Dep2Color = new ExPar(DEPCOLOR, new ExParValue (PxlColor.black),
                          "Second Dependent Color");
    public ExPar Dep3Color = new ExPar(DEPCOLOR, new ExParValue (PxlColor.black),
                          "Third Dependent Color");
    public ExPar Dep4Color = new ExPar(DEPCOLOR, new ExParValue (PxlColor.black),
                          "Fourth Dependent Color");

Note that the dependent colors get the type code DEPCOLOR to indicate that these are not adjustable. The method computeColors() computes the colors Dep1Color to Dep4Color as a mixture of the colors Square1Color to Square3Color:

    protected void computeColors() {
	Dep1Color.set(Square1Color.getPxlColor().add(Square2Color.getPxlColor()));
        Dep2Color.set(Square2Color.getPxlColor().add(Square3Color.getPxlColor()));
        Dep3Color.set(Square3Color.getPxlColor().add(Square1Color.getPxlColor()));
        Dep4Color.set(Dep1Color.getPxlColor().add(Square3Color.getPxlColor()));
    }

The class PxlColor has a method which creates the additive mixture of two colors:

   color1.add(color2)
returns the additive mixture of color1 and color2 where both are PxlColor objects. So
   Square1Color.getPxlColor().add(Square2Color.getPxlColor())
retrieves the colors coordinates from the experimental parameters Square1Color and Square2Color and computes their additive mixture.

Note that while the methods create() and computeGeometry() are defined abstract in the class Display the method computeColors() is not. Thus concrete subclasses of Display need not implement computeColors() if they do not need to compute dependent colors.

Standard Painting

In many cases it will not be necessary to do any painting by the display itself. The superclass Display does that by walking through the list of display elements and drawing them using the information contained in each DisplayElement object. Thus most subclasses of Display will not have any paint methods. However, if the standard way of painting is not sufficient then a display may override the method

    public void showGroup(Graphics g)
of class Display to do its own painting. Here is the code for the class Display's painting method which is simple enough:
    public void showGroup(Graphics g) {
	setGraphicsContext(g);
	showBackgroundElement();
	showGroup();
    }

This method first sets the drawing context and then paints the background. Display element painting actually is delegated to the method showGroup() which has this code:

    public void showGroup() {
	if (ExPar.Stereographic.getFlag()) {
	    showGroupStereo();
	} else {
	    DisplayElement de;
            long timingGroupPattern;
            int n = displayElementList.size();
            for (int i = 0; i < n; i++) {
	        de = (DisplayElement)displayElementList.get(i);
	        timingGroupPattern = de.getTimingGroupPattern();
	        if ((timingGroupPattern & activeTimingGroup) != 0L) {
		    de.show();
		    updateBoundingBox(de.getBounds());
	        }
	    }
	}
    }

For non-stereo display objects this method walks through the list of display elements and calls their method show() if the respective display element is a member of the current timing group.

The class Display also has methods to paint display objects which ignore the timing groups. These are used by display editors but not by experimental runtime controllers.

Any display object which is not easily composed of objects from the DisplayElement class may override the above painting methods to do more complicated painting. Here is an example from class SearchPattern which overrides showGroup() in order to allow subclasses to override the methods for showing targets and distractors:

    protected void showGroup() {
	show();
    }
    public void show() {
	boolean showTarget = ShowTarget.getFlag();
	graphics.setColor(DistractorColor.getDevColor());
	for (int i = 0; i < (nItems-1); i++) showDistractorAt(positionOfItem(i));
	if (showTarget) {
	    graphics.setColor(TargetColor.getDevColor());
	    showTargetAt(positionOfItem(nItems-1));
	} else {
	    showDistractorAt(positionOfItem(nItems-1));
	}
    }
    protected void showDistractorAt(Point p) {
	graphics.fillOval(p.x, p.y, itemSize, itemSize);
    }
    protected void showTargetAt(Point p) {
	graphics.fillOval(p.x, p.y, itemSize, itemSize);
    }

Note that both methods show() and showGroup() are overriden which is possible since this display has only a single timing group. The advantage is that both experimental runtime controllers and display editors are able to correctly show the display object.

Display Element Properties

The display elements available have been described earlier. Each display element has the following methods to set/get its location on the screen and its size:
    public void setLocation(Point l);
    public void setLocation(int x, int y);
    public Point getLocation();
    public void setSize(Dimension s);
    public void setSize(int width, int height);
    public Dimension getSize();
    public void setRect(Rectangle r);
    public void setRect(Point p, Dimension s);
    public void setRect(int x, int y, int width, int height);
    public void setCenterAndSize(int x, int y, int width, int height);

Every display element has its own method to show itself:

    abstract public void show();
This method must be defined by every subclass. A display element may also be shown in a color which differs from the one which has originally been assigned to it:
    public void show(ExPar i);
Further display element properties depend on the type of display element and may be found by looking at ther respective API document.

Simple Geometric Shapes

The most commonly used type of geometric objects in PXLab's displays are filled geometric shapes. These are objects of type Bar(), Oval(), FilledPolygon()and Sector(). Outlined object types are Line(), Rect(), Ellipse(), PolyLine(), PolyLineClosed(), and Arc(). Bar, Oval, Rect, and Ellipse objects are completely defined by their location and size. FilledPolygon, PolyLine, and PolyLineClosed objects are subclasses of class DisplayElementPolygon and are defined by setting their Polygon:
     public void setPolygon(Polygon p);

The location and size parameters are not used in this case.

The classes Arc and Sector are subclasses of DisplayElementArc and their parameters for the starting angle and the angle size are set by calling setAngles():

    public void setAngles(int startAngle, int arcAngle) {

Text Elements

There are two major text elements: TextElement and TextParagraphElement. The TextElement is a single line of text while TextElement is a multiline paragraph of text which can do its own line breaking. These objects use the location parameter defined earlier but do not use the size parameter. Their size is defined by setting the font of the text object:

    public void setFont(String fn, int ft, int fs);

Every text object has reference point which defines how the location parameter of the text object is interpreted:

    public static void setReferencePoint(int p)

By default the location parameter specifies the left edge base line point of the text string. Other values may be set such that the location refers for example to the center base line point of a string. These values are available:

    public static final int BASE_LEFT    public static final int MIDDLE_LEFT    public static final int TOP_LEFT    public static final int BASE_CENTER    public static final int MIDDLE_CENTER    public static final int TOP_CENTER    public static final int BASE_RIGHT    public static final int MIDDLE_RIGHT    public static final int TOP_RIGHT

Here the terms LEFT, CENTER, and RIGHT refer to the horizontal position while BASE, MIDDLE, and TOP refer to the vertical position. Note that the reference point of a text paragraph refers to the paragraph as a whole and not to a single line.

When using a text object then the drawing color will usually be defined in a display's create() method:

	text_idx = enterDisplayElement(new Text(Color));

Since all size dependent parameters of a display should be defined in the method computeGeometry() this should be the place where to define the font and the location of the text object. The string content of the text should also be defined in the method computeGeometry() since only then can the string be reinitialized repeatedly from experimental parameters. The following example is from the class TextParagraph which creates a display containing a text paragraph:

    protected int textpar;

    protected int create() {
	textpar = enterDisplayElement(new TextParagraphElement(this.Color), group[0]);
	defaultTiming(0);
	return(textpar);
    }

    protected void computeGeometry() {
	double w = Width.getDouble();
	int ww = (w < 1.0)? (int)(width * w): (int)w;
	((TextParagraphElement)getDisplayElement(textpar)).setProperties(
            Text.getStringArray(),
            FontFamily.getString(), FontStyle.getInt(), FontSize.getInt(),
            LocationX.getInt(), LocationY.getInt(),
	    ww,
            ReferencePoint.getInt(),
	    Alignment.getInt(), 
            (Wrapping.getInt() != 0),
            LineSkipFactor.getDouble());
    }

This creates a single paragraph of text. Note that the method setProperties() of class TextParagraphElement also accepts parameters to set the formatting style, line wrapping and line skip. Text paragraphs also need to know the intended width in order to do line breaking. The text of a text paragraph may be a single string or an array of strings. A single string may contain line break characters '\n' to force line breaks. The elements of a string array always force line breaks.

Picture

Picture objects are rectangular arrays of pixels and differ from all other objects in that they ignore the color parameter. They have their colors coded into the image pattern. Picture objects use the location parameter to define the top left position of the image but they do not use the size parameter since the picture's size is derived from the number of horizontal and vertical pixels. Pictures may be loaded from files or they may be created by drawing into an image buffer and connect this buffer to the picture. Here is an example from a sinusoidal grating which is created by drawing into an image buffer. During create() the display element is defined to be a Picture object:

    private int s1, s2;

    protected int create() {
	Picture pict = new Picture();
	pict.setColorPar(AColor);
	s1 = enterDisplayElement(pict, group[0]);
	defaultTiming(0); 
	return(s1);
    }

    protected void computeColors() {
	computeGeometry();
    }

There also are two color parameters defined. These are used to compute the sinusoid which is a smooth transition from AColor to BColor. Here is the complete method for creating this picture object:

    Image imageBuffer;
    int x, y, w, h, w4;

    protected void computeGeometry() {
	Rectangle r = largeSquare(width, height);
	w4 = r.width/4;
	w = w4 + w4 - 1;
	h = r.height/2;
	x = r.x + w4;
	y = r.y + r.height/4;
	setFramesPerCycle(w-1);
	int fd = FrameDelay.getInt();
	setFrameDelay(fd);
	int fi = FrameIncrement.getInt();
	setFrameIncrement(fi);
	PxlColor[] ramp = AColor.getPxlColor().sinusoidalRampTo(
                          BColor.getPxlColor(), w4);
	imageBuffer = displayPanel.createImage(4*w4-1, h);
	Graphics g = imageBuffer.getGraphics();
	for (int x = 0; x < w4; x++) {
	    g.setColor(ramp[x].dev());
	    g.drawLine(x, 0, x, h-1);
	    if (x < (w4-1)) g.drawLine(w-x-1, 0, w-x-1, h-1);
	    if (x > 0) g.drawLine(w+x-1, 0, w+x-1, h-1);
	    if ((x > 0) && (x < (w4-1))) g.drawLine(4*w4-4-x, 0, 4*w4-4-x, h-1);
	}
	Picture p = (Picture)getDisplayElement(s1);
	p.setImage(imageBuffer, displayPanel);
	p.setLocation(x, y);
	p.setClipRect(x, y, w, h);
    }

It starts with computing the location and size of the picture. These are used to define the picture's clipping rectangle. The clipping rectangle defines that subsection of the image which actually is shown on the screen. This is used here since our image will be larger than the displayed picture. Then the number of frames per display cycle and delay time between successive frames for the animation are set. The color transition is computed by creating a sinusoidal ramp from color AColor to color BColor. Finally an image buffer of the appropriate size and a Graphics context for this buffer is created. Then the colors in the sinusoidal ramp array are used to draw the image lines into the buffer. Note that two periods are drawn since this makes it possible to shift the display window across the buffer during animation.

The standard show() method of a picture object uses the location to position the picture and also sets the clipping rectangle if it is defined.

Subgroups of Display Elements

Every display contains a list of display elements. A display can define groups of display elements by adding a group pattern parameter to the display element when it is entered into the display element list. These groups are called timing groups because all members of a single group are always shown simultanously on the screen. A single display element may belong to more than a single timing group. A simple example is contained in the class TwoStrings which can show two lines of text with an SOA:

    private int signal, probe;

    protected int create() {
	signal = enterDisplayElement(new TextElement(SignalColor), group[0]+group[1]);
	int t = enterTiming(SOATimer, SOADuration, 0);
	probe = enterDisplayElement(new TextElement(ProbeColor), group[1]);
	t = enterTiming(Timer, Duration, ResponseSet, t, ResponseTime, ResponseCode);
	return(signal);
    }

The intention of this display is to first show a single line of text ("signal") and then after a certain SOA to add another line of text. This display contains two timing groups: the first group only contains the signal text and the second group both contains the signal and the probe text. Note that every timing group has its own timer and duration parameters. Only the second timing group explicitly sets its response parameter names since the response will be connected to the second timing group. No special drawing code needs to be written. The usual geometry parameters are set by the computeGeometry() method:

    protected void computeGeometry() {
	String fnn = FontFamily.getString();
	int fnt = FontStyle.getInt();
	TextElement txt;
	txt = (TextElement)getDisplayElement(probe);
	txt.setFont(fnn, fnt, ProbeSize.getInt());
	txt.setLocation(ProbeLocationX.getInt(), ProbeLocationY.getInt());
	txt.setText(ProbeText.getString());
	txt = (TextElement)getDisplayElement(signal);
	txt.setFont(fnn, fnt, SignalSize.getInt());
	txt.setLocation(SignalLocationX.getInt(), SignalLocationY.getInt());
	txt.setText(SignalText.getString());
    }

Animated Displays

Display objects may be animated. Animations run in their own thread which is controlled by the realtime display controller. A display which may be animated has to tell this by overriding the method isAnimated():

    public boolean isAnimated() {return(true);}

Animation is done frame by frame where a single frame corresponds to a single image of the animation movie. Animations usually are cyclic and the display tells the superclass how many frames constitute a single display cycle by using method

    public void setFramesPerCycle(int fpc)

This is usually done from within a display's create() method. Animation speed may be controlled by timing parameters. Here is an example of the MovingDot() class:

    private int dot;

    protected int create() {
	dot = enterDisplayElement(new Oval(Color), group[0]);
	int t = enterTiming(OnOffTimer, OnDuration, 0);
	enterDisplayElement(new Clear(), group[1]);
	enterTiming(OnOffTimer, OffDuration, t);
	setFramesPerCycle(2);
	return(dot);
    }

It contains two display elements: a dot and a clear screen object which belong to different timing groups and the timing group timer and duration parameters determine the duration of a single frame. Computing the geometric properties of this display is simple and does not differ from displays which are not animated:

    private int leftX, rightX, dotSize;

    protected void computeGeometry() {
	int d = Distance.getInt();
	dotSize = Size.getInt();
	leftX = -d/2;
	rightX = d/2;
	getDisplayElement(dot).setCenterAndSize(leftX, 0, dotSize, dotSize);
    }

The only additional method which must be provided by the animated display's own class is the method

    public void computeAnimationFrame(int frame);
which has to recompute the geometric properties of the display such that it shows the given frame number. In our example the successive frames differ only by the horizontal position of the dot:
    public void computeAnimationFrame(int frame) {
	getDisplayElement(dot).setCenterAndSize((frame == 0)? leftX: rightX, 0, dotSize, dotSize);
    }

[This file was last updated on July 15, 2010, 12:07:01.]

[Home]    [Content]    [Previous Chapter]    [Next Chapter]