devxlogo

Powerful Printing in Flash MX 2004

Powerful Printing in Flash MX 2004

t is no longer neccessary to creatively twist and bend Flash’s printing APIs to perform the more complex printing tasks like multi-page printing. Thanks to ActionScript 2.0 and Flash Player 7, you now have direct access to a rich set of print functionality. This article explores these powerful new functions and discusses how to structure application code to take full advantage of them.

This previous article, discussing Flash Player 5, outlined a set of code strategies for printing in Flash and those techniques have aged well. Reading the previous article isn’t a prerequisite, but it’s not a bad idea, as this article uses the same design strategy to organize application code in a manner that makes printing even simpler and the code even more maintainable.

The PrintJob Class
The big change introduced by Flash Player 7 is the PrintJob class. PrintJob has three methods: start(), addPage(), and send() which are called during the course of printing. The standard boilerplate code looks like this:

var printJob:PrintJob = new PrintJob();if (printJob.start()) {var numPages:Number = 0;if (printJob.addPage(aMovieClip)) {numPages ++;}// etc.if (numPages> 0) {printJob.send();  // print page(s)}}delete printJob;  

The numPages variable counts the pages as they are added, and ensures that at least one call to addPage() succeeds before it calls PrintJob.send(). In addition, the addPage() method can take three optional parameters after the initial movie clip parameter (which is required). Those additional arguments are: a bounding box for the print area, a parameter letting Flash know whether to print as vector or bitmap, and a frame number to print. While ActionScript 2.0’s documentation covers those parameters in more depth, using the techniques described below should mean that you won’t have to use those additional parameters very often.

Though the actual ActionScript printing classes and methods are straightforward, how best to use them is not. The previous article outlines a technique for printing that involves copying movie clips dynamically to off-screen, pre-drawn printing interfaces?instead of printing what was on the actual user-interface. This strategy provides a much more stable and controllable printing process.

A Flash Drawing Application
This article uses the same application as the previous article, a Flash application for drawing. Take a look at the user interface in Figure 1, which contains a color selector, a tool palette, a “print” button, and a main interface where the drawing occurs.

Figure 1. The User Interface: The app’s user interface contains a color selector, a tool palette, a “print” button, and a main interface where the drawing occurs.

Figure 1 shows not one, but actually three user interfaces. The interface at the top is the one the user interacts with, while the two below are hidden offscreen and used only for printing (the major movie clips are labeled with their instance names in [brackets] for easy reference). This means that the two printing interfaces are only ever visible to the user in printouts.

This is possible because Flash is not limited to printing what is on-screen; in Flash, you can create movie clips offscreen and then print those offscreen clips. The movie clip to the bottom left (printArea1) is a cover sheet for the movie clip to the bottom right (printArea2), where the user’s actual drawing is printed. This example complicates things further by placing a smaller sized “preview” of the drawing on the cover sheet in the center (the box labeled printPreview).

All told, you have three interfaces in to draw circles: on the main interface and on each of the two print interfaces. The question is: how to do this in the most efficient and maintainable fashion? Start by creating a place to store information about the shapes a user has drawn. To do that, create a class called Circle with three properties: x-position (x), y-position (y), and color (c):

class Circle {	var x:Number;	var y:Number;	var c:Number;		// constructor	function Circle(x:Number, y:Number, c:Number) {		this.x = x;		this.y = y;		this.c = c;	}		function getX():Number {		return this.x;	}	// etc.

The full source code contains a “getter” method for each of the three properties that follows the example of the getX() method above. ActionScript 2.0’s class definitions are held outside the main application, so the main Flash file imports the Circle class creates an array in which to store circles:

import Circle;var circles = Array();

Adding Drawing Code
When the user clicks on the drawing interface (drawArea), look up the color selected, create a new Circle object, and then add the circle to the array of circles:

drawArea.onPress = function() {	var c;	switch (colorGroup.getValue()) {		case "red":   c = 0xFF0000; break;		case "green": c = 0x00FF00; break;		case "blue":  c = 0x0000FF; break;	}		var circle:Circle = new Circle(drawArea._xmouse,drawArea._ymouse,c);	circles.push(circle);

Note that you have not actually drawn anything, but just stored the information about the new circle. The drawing comes in the very next line that concludes the function:

	update(drawArea); };

What’s going on here? You’ve delegated drawing to the update() function, sending in the name of the clip in which the circles are to be drawn?in this case, drawArea. The update() function does the actual drawing:

// draws the circles on the movie clip providedfunction update(mc) {	for (var i=0;i

Note that this function takes a movie clip as an argument, so it can draw circles on any movie clip, not just the drawArea clip. By organizing your code in this fashion, you avoid repeating the code for drawing the circles. That is, you can use this same method for preparing your printouts of the drawing.

Here is the print function, wired to the "print" button on the main interface. As you can see, this function starts off with two calls to update(), once for each of the print pages:

printButton.onPress = function() {	// prepare the printing area	update(printArea1.printPreview);	update(printArea2);		// shrink the preview	printArea1.printPreview._xscale = 25;	printArea1.printPreview._yscale = 25;		printArea1.dateField.text = new Date();		var printJob:PrintJob = new PrintJob();	if (printJob.start()) {  		var numPages:Number = 0;		if (printJob.addPage(printArea1)) { numPages++; }		if (printJob.addPage(printArea2)) { numPages++; }		if (numPages > 0) {			printJob.send();		}		delete printJob;	}}
Figure 2. The Offscreen Clips: Pressing the print button copies the drawing twice to the offscreen clips.

After the calls to update(), which render the circles on the offscreen movie clips, shrink the print preview movie clip to one quarter og its original dimensions so that it appears smaller?like a preview should. The rest is just the PrintJob boilerplate code from above. So when you press the print button, two new copies of the drawing are made to the offscreen clips. Figure 2 shows a screenshot taken from within the Flash Player that exposes these offscreen areas.

For a closer look, the entire source code is shown in Listing 1.

The code that draws the user interface also handles the assembly of the print interfaces. The result is less code, clearer design, and a more maintainable application. The strategy of isolating the drawing code from any specific references to where to draw is a common design practice and can be useful in many Flash applications. Java developers may recognize this same design scheme in the Java Abstract Window Toolkit (AWT), where the paint() method that draws interfaces always takes a Graphics object that tells Java where to draw. It is a design pattern that?among other things?works well in Flash and makes printing a lot easier.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist