ORIGINAL DRAFT
This month’s installment is a fun component based on visual transitions between two images. This is the kind of thing you’re used to seeing on television. There are, of course, an endless number of tricks you can use to transition between images. Our primary focus will be on the Transition interface and a few example implementations. Microsoft’s PowerPoint supports this kind of transition capability between slides, as do other presentation applications.You can use this feature any time you have two images to transition between.
One of the obvious assumptions is that you have two images of the same size, though our code will deal with divergent sizes well enough. Figure 1 shows an overlay transition midway through its sequence. The smaller image at the lower left is scaled because we’ve selected a Size-based transition. It is coming in, rather than going out, because we chose that direction in the bottom left pulldown menu. Finally, the image is coming in toward the North and East. The JTransitionTest example allows you to select the vertical and horizontal direction, whether the image is coming in or going out, and whether the the transition clips the incoming image, moves in it or out, or whether it scales the size on the way in or out.
Figure 2 shows the classes we’ll implement in this article. We use a common Transition interface to make it possible to plug in any transition we can invent using the same basic model. The TransitionConstants are kept separate because they may not apply to all Transition implementations, though they do apply to the ones in this article. We use an AbstractTransition class to implement some of the common behavior shared by the other implementations. Each of our example transitions extend the OverlayTransition class. This is not a limitation of the interface but rather of the time I was able to spend coming up with examples.
The Transition interface is very simple, allowing us to set a source and target image and call a simple transition method to actually execute the effect. The component argument is required so that we can get a reference to the Graphics object.
public interface Transition
{
public void setSourceImage(Image source);
public void setTargetImage(Image target);
public void transition(Component comp);
}
Listing 1 shows the source code for the AbstractTransition class. Pretty much any Transition we’re likely to implement has to store a reference to the source and target images, so we handle this in a common class. Another common operation is a pause for a specified number of milliseconds. We use this method to pause between frames so that the transition is not displayed too quickly. A final utility method called invertDirection returns the opposite direction for NORTH, SOUTH, EAST and WEST, returning the same value if the input is any other integer.
With our AbstractTransition complete, we can implement a set of overlapping transitions to demonstrate how you can apply the Transition interface in practice. OverlapTransition expects a number of values in the constructor, aside from the source and target images. The type determines whether we are dealing with a MOVE, CLIP or SIZE transition. The vert and horz values represent whether we are moving from the NORTH or SOUTH and/or EAST or WEST, respectively. The inout value is either IN or OUT indicating whether the image is moving inward from the outside or vice versa. We can also define the number of steps we’d like to see (this is the number of frames), as well as the interval (in milliseconds) between frames.
Listing 2 shows the OverlapTransition class. The transition method steps through each frame by calling the drawFrames method. The drawFrames method, in turn, calls the drawCell method for each rectangular cell on display. You’ll notice that we don’t do standard paint or paintComponent calls to do this work. Instead we draw directly into the graphic context because we want to see the display take place immediately. If we didn’t do this, basic Java, Swing or OS paint optimizations might get in the way and cause transitions to skip frames or lose fluidity.
If you take a close look at the drawCell method, you’ll see that each cell drawing depends on the rectangular area the cell encompasses as well as the type (MOVE, CLIP or SIZE) setting and the vertical and horizontal direction indicators. At the end of all the numerical adjustments, we end up with a drawImage call that draws a portion of the cell image or a scaled version. The destination image uses variables prefixed by the ‘d’ character and the source image has an ‘s’ prefix to make the code more readable.
The drawCells method is shared by each of the OverlapTransition subclasses. Because the subclasses involve nothing more than a few alternating directional flips, only the drawFrames methods need to be implement. The SplitTransition class allows you to have vertical or horizontal transitions moving in opposing directions. A typical transition might look like a curtain opening or closing. The QuadrantTransition further mirrors the second axis, so that the result looks more like a box opening or closing. Figure 3 shows the second image moving out toward the corners, leaving the target image behind.
The final Transition implementation I’ve developed is called GridTransition. It divides the image into an arbitrary number of cells, defined as a given number of vertical and horizontal divisions. The GridTransition is used to demonstrate the vertical and horizontal bar options as well, by using a single division on the least significant axis. Both the 5 x 5 and 20 x 20 examples in the test class also use it.
Of course, none of this is useful if we don’t have a good framework for presenting transitions. That’s where the JTransition component, in Listing 3, comes into play. It is designed to accept a source and target image and an instance of the Transition interface. Once you have an instance, you can set or get the transition or call the transition method to execute the visual effect. To make it easy to transition back to the first image without undue complexity, we implement a flipSourceAndTarget method. You can also control which image is being displayed by calling the showSource and showTarget methods.
When you download the online code, you’ll find a JTransitionTest class. It’s what you see in the screen captures I’ve tried to use for demonstration purposes. It works by assigning Transition instances to a multi-dimensional array and using the pulldown menu indexes to select the Transition to use. When you press the Show button, the transition executes. Keep in mind that when you first run it the vertical and horizontal selectors are set to NONE, so you need to flip at least one of those to see anything useful. In any case, it think you’ll find it pretty entertaining to play with the various settings just to see what each transition can look like.
There are an endless number of possible transitions you could add to this interface. A few obvious choices include a growing and/or shrinking circle/oval transition; a rippling transition; a lens effect; random pixelation/replacement; rolling corner/page turns; puzzle pieces; three dimensional rotations; cube turns; spherical wraps; etc. If you’re working with presentation software, you’ll need something like this along the way. You can use this component and the Transition interface to implement Easter eggs, fancy ‘about’ dialog windows, special visual effects, or whatever you see fit to present to your users. I hope you have as much fun with this as I plan to have when I implement a few more of these cool Transitions.