Printing in Adobe Flex Using the FlexPrintJob Class

Printing in Flex is actually pretty simple and allows for a print view to be set up that may not look anything like the application UI displayed on screen. This allows for loosely coupled design and also multiple different print views if desired.

To begin, I created an MXML component that was the print view as I wanted it to look coming out of the printer. The code was located in a file called “DriPrintCanvas.mxml”. The code is as follows:

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas 
	xmlns:mx="http://www.adobe.com/2006/mxml"
	backgroundColor="#FFFFFF"
>
	<mx:Binding 
		source="genderText" 
		destination="genderLabel.text" 
	/>
	<mx:Binding 
		source="lifeStageText" 
		destination="lifeStageLabel.text" 
	/>
	<mx:Binding 
		source="firstNameText" 
		destination="firstNameLabel.text" 
	/>
	<mx:Binding
		source="lastNameText"
		destination="lastNameLabel.text"
	/>
	<mx:Binding 
		source="resultsDataProvider" 
		destination="resultsDataGrid.dataProvider" 
	/>
	<mx:VBox
		left="70"
		right="70"
		top="20"
		bottom="20"
	>
		<mx:Label
			text="Nutrition in Medicine"
			textAlign="center"
			fontSize="24"
		 width="100%"/>
		<mx:Label 
			text="Nutrient Intake Recommendations for Healthy People"
			textAlign="center"
			fontSize="14"
		 width="100%"/>
		<mx:HBox right="70" left="70" top="20" width="100%">
			<mx:VBox 
				left="40" 
				top="20"
	 			width="50%"
	 		>
				<mx:HBox width="100%">
					<mx:Label text="Name:"/>
					<mx:Label id="firstNameLabel"/>
					<mx:Label id="lastNameLabel"/>
				</mx:HBox>
				<mx:HBox width="100%">
					<mx:Label text="Age Group:"/>
					<mx:Label id="lifeStageLabel"/>
				</mx:HBox>
				<mx:HBox width="100%">
					<mx:Label text="Gender:"/>
					<mx:Label id="genderLabel"/>
				</mx:HBox>
			</mx:VBox>
			<mx:VBox y="20" right="40" width="50%" cornerRadius="0" borderStyle="solid" borderColor="#000000">
				<mx:Label text="Legend:" width="100%"/>
				<mx:Text text="*Represents an Adequate Intake value."/>
				<mx:Text text="s: from supplements"/>
			</mx:VBox>
		</mx:HBox>
		<mx:Spacer height="20" />
		<mx:PrintDataGrid id="resultsDataGrid" 
			width="100%"
			color="#000000"
		 sizeToPage="true">
			<mx:columns>
				<mx:DataGridColumn 
					headerText="Nutrient" 
					dataField="nutrient"
					width="0.3"
				/>
				<mx:DataGridColumn 
					headerText="Target" 
					dataField="target" 
					itemRenderer="components.TargetItemRenderer" 
					textAlign="right"
					width="0.25"
				/>
				<mx:DataGridColumn
					headerText="Units"
					dataField="units"
					width="0.1"
				/>
				<mx:DataGridColumn
					headerText="Upper Limit"
					dataField="upperLimit"
					textAlign="right"
					width="0.25"
				/>
				<mx:DataGridColumn
					headerText="Units"
					dataField="units"
					width="0.1"
				/>
			</mx:columns>
		</mx:PrintDataGrid>
	</mx:VBox>
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			
			private var _genderText:String;
			private var _lifeStageText:String;
			private var _firstNameText:String;
			private var _lastNameText:String;
			private var _resultsDataProvider:ArrayCollection;
			
			[Bindable]
			public function get genderText():String
			{
				return _genderText;
			}
			public function set genderText(value:String):void
			{
				_genderText = value;
			}
			
			[Bindable]
			public function get lifeStageText():String
			{
				return _lifeStageText;
			}
			public function set lifeStageText(value:String):void
			{
				_lifeStageText = value;
			}
			
			[Bindable]
			public function get firstNameText():String
			{
				return _firstNameText;
			}
			public function set firstNameText(value:String):void
			{
				_firstNameText = value;
			}
			
			[Bindable]
			public function get lastNameText():String
			{
				return _lastNameText;
			}
			public function set lastNameText(value:String):void
			{
				_lastNameText = value;
			}
			
			[Bindable]
			public function get resultsDataProvider():ArrayCollection
			{
				return _resultsDataProvider;
			}
			public function set resultsDataProvider(value:ArrayCollection):void
			{
				_resultsDataProvider = value;
			}
		]]>
	</mx:Script>
</mx:Canvas>

There is a lot here but basically the important things to note are the several properties of the component that can be set using the setters, such as genderText, firstNameText, lastNameText, resultsDataProvider, etc. When it comes time to printing these will be the items that get set at runtime to be displayed in the printout. Also note that a PrintDataGrid is used rather than a normal DataGrid. They are essentially the same, however, the PrintDataGrid tries to arrange itself for printing and also attempts to not widow rows on another page.

The next step is to write the printing code using the FlexPrintJob class found in the mx.printing library. The code was in a file called DriSelectorPrintJob.as and is included below:

package components
{
	import mx.containers.Canvas;
	import mx.core.Application;
	import mx.printing.FlexPrintJob;
	import mx.controls.Alert;
	
	public class DriSelectorPrintJob
	{
		public function DriSelectorPrintJob(printCanvas:DriPrintCanvas)
		{
			
			printCanvas.visible = true;
			print(printCanvas);
		}
		
		private function print(canvas:DriPrintCanvas):void
		{
			var pagesToPrint:uint = 0;
			var printJob:FlexPrintJob = new FlexPrintJob();
			
			if (printJob.start())
			{
				try
				{
					Application.application.addChild(canvas);
					canvas.height = printJob.pageHeight;
					canvas.width = printJob.pageWidth;
					printJob.addObject(canvas);
					pagesToPrint++;
				}
				catch (e:Error)
				{
					Alert.show("Print error", e.message);
				}
				if (pagesToPrint &gt; 0)
				{
					printJob.send();
				}
				Application.application.removeChild(canvas);
			}
		}
	}
}

To begin, an instance of the DriPrintCanvas, created in the first step, was passed to the constructor of the DriSelectorPrintJob class. Note that the various properties of the DriPrintCanvas instance have already been set before it was passed to the constructor. The printCanvas’s visible property is then set to true to ensure that it will be visible in the application (this may not be necessary, but I included it to be safe).

Next, the print method is called, passing the printCanvas along. I designed this method so that in the future it could be easily modified to include printing more than one page, hence the pageCount variable. This method, however, does not include that functionality at this point. A FlexPrintJob instance is created and the start method is called within an if statement. This is important because the method will return true if the user clicks OK in the print dialog box or false if the user clicks Cancel.

In order for the printCanvas to be visible to Flex, it must be included somewhere within the application’s visible child components. To make this work, the Application.application.addChild() method must be used.

The height and width of the canvas were then set to match the height and width of the printJob. These values are retrieved from the printer settings.

The addObject method of the printJob was called with the printCanvas as the argument. This adds the printCanvas to the printJob. In the Flex API, this method is overloaded and may also take a second argument that specifies how to scale the object being added when it is sized to the page. I was not able to get this method to work when including the second argument.

The pagesToPrint count is incremented and then if it is greater than 0, the printJob’s send method is called, which sends the print job to the printer. Do not forget to remove the printCanvas from the application’s child components at the end.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: