PXLab Manual
[Home] [Content] [Previous Chapter] [Next Chapter]
The PXLab Software APIPXLab 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
jpxlin 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 bec:/jpxl/srcin 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
scrdirectory contains the build file namedbuild.xmland two subdirectories:shareandwin32. Thesharesubdirectory contains all shared sources and thewin32subdirectory contains the Windows native DLL sources for the librarypxlab.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
jdkof a directory namedjavasofton 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 usingjdkmakes 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
antof ourjavasoftdirectory. To get this we extract the Ant archive into directoryjavasoftand rename the resulting release dependent directory name toant.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
javaccof thejavasoftdirectory. 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:
- Download the zip-archive javacomm20-win32.zip (274.432 Bytes) for Windows.
- Unpacking the archive gives you three files:
where 'JRE' stands for the installation directory of your Java runtime environment which will in our default case be
- move
win32com.dllintoJRE/bin- move
comm.jarintoJRE/lib/ext- move
javax.comm.propertiesintoJRE/libC:/javasoft/jdk/jre/. All other files of the archive are documentation.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
jmfof thejavasoftdirectory.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 namedbatik.jarwhich you will find in subdirectorysrc/share/extof the PXLab source archive. Move this file into the same location (jdk/jre/lib/ext) as described earlier for the filecomm.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.batcontained in directoryjpxl/src/binwhich 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 directoryjpxl/srcand 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:
- a constructor for instantiating subclass objects;
- the method
create()to set up the lists of display and timing elements;- the method
computeGeometry()for computing the geometric properties of the display elements contained in the display.These methods are
abstractmethods 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 aspublicExPar 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 methodprotected int create()which is called by the Display manager after selection or by experimental runtime controllers when an experiment is being prepared. The methodcreate()does the following initializations:
- prepare the list of DisplayElement objects which make up the display's geometry and associate a color parameter with each display element;
- defined the timing group of each display element;
- define the timing properties of each timing group contained in the list of display elements;
- return the index of the first active display element after startup.
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 methodprotected 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:
- Arc() is an arc from an ellipse.
- AudioBeep() is a simple acoustic signal.
- Bar() is a filled rectangle.
- BarPattern() is a series of filled rectangles.
- BinaryRandomDotArray() is a binary random dot pattern.
- BitMap() is a bit image.
- CharPattern() is a series of characters.
- CharPatternMask() is a masked created by a series of characters.
- Clear() is a clear screen object.
- ColorSampleView() is a view of a rectangular pattern of color samples.
- Cross() is a cross.
- DotGrid() is a grid of dots.
- Ellipse() is an outlined ellipse.
- EmptyDisplayElement() is a display element which does not change the screen when 'painted'.
- ExternalControlSignal() controls external signals and lines.
- FilledPolygon() is a filled polygon.
- Grating() is a sinusoidal grating pattern.
- Grid() is a series of horizontal or vertical bars.
- HorStripedBar() is a series of horizontal stripes.
- IlluminationDeviceControlElement() controls an illumination device.
- LightDistribution() is a spatialmixture of light sources.
- Line() is a simple line.
- Oval() is a filled ellipse.
- Patch() is an filled patch which is selectable and changes from rectangular to elliptical when selected.
- Picture() is an image contained in a file.
- PolyLine() is a sequence of lines.
- PolyLine2D() is a sequence of lines drawn with antialiasing.
- PolyLineClosed() is a closed sequence of connected lines.
- RandomDotArray() is a rectangular random dot pattern.
- RandomTiles() is an area filled with random sized rectangles.
- RegularTiles() is an area filled with regular rectangles.
- Rect() is an outlined rectangle.
- RulerElement() is a ruler.
- Scale() is a series of scale marks.
- Sector() is a filled sector of an ellipse.
- SingleCharPattern() is a pattern made up from a single character.
- SmoothDisk() is a filled disk with a smooth contour.
- SoundFileElement() plays a sound file.
- SoundRecorderElement() records sound.
- SyntheticSoundElement() plays synthetic sound.
- TextElement() is a single line of text.
- TextParagraphElement() is a paragraph of text.
- VerStripedBar() is a series of vertical stripes.
- VisualGammaPattern() is a pattern to visually determine the monitor's gamma parameters.
- VoiceKeyElement() is a voice key.
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:
setLocation(int x, int y)for defining the position within the display,setSize(int w, int h)for defining the width and height,setRect(int x, int y, int w, int h)both sets the location and the size of a display element.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 getsgroup[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 methodprotected void computeGeometry()This method is called by the realtime display controller. Before calling thecomputeGeometry()method the display controller sets the fieldswidthandheightof the activeDisplayobject. Here is a simple example forcomputeGeometry():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 methodgetDisplayElement()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 expressiongetDisplayElement(bar_idx)which gets us the DisplayElement object at indexbar_idxin this display's list of display elements. The class DisplayElement uses the methodsetRect()to set a Bar's location and size. Thusbar.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 methodcomputeGeometry()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
PxlColorhas a method which creates the additive mixture of two colors:color1.add(color2)returns the additive mixture ofcolor1andcolor2where both arePxlColorobjects. SoSquare1Color.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()andcomputeGeometry()are definedabstractin the class Display the methodcomputeColors()is not. Thus concrete subclasses of Display need not implementcomputeColors()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 theirPolygon: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_RIGHTHere 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 methodcomputeGeometry()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
Graphicscontext 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]
![]()