Flex DataGrid Printing

Posted: January 6, 2007 in Flex

Hi Fellow Developers,

A couple nights ago I attended a CAFUG (Capital Area Flex User Group) meeting in Rockville. If you live in the area, want to learn about Flex, and meet with a great group of people I suggest that you attend the next meeting. Well, in the last meeting Scott Stroz did a wonderful presentation on the tips, tricks, and pitfalls of printing from Flex. One of his sample apps show users how to properly print data in a DataGrid (go to thier web site to download the code). For those of you who may not know how to properly print data in a Flex DataGrid, Flex provides an special DataGrid class used for printing. It’s called the PrintDataGrid class. You create a PrintDataGrid component instance to mirror the UI DataGrid. Only, the PrintDataGrid contain no user interaction capabilities. It is strictly used for printing DataGrid data.

So, a little voice inside my head said, “Why should I have to create one DataGrid for display and one for printing. I should be able to use the display DataGrid to “spawn” a printable DataGrid instance. Well as they say, “like white on rice”, I was on it. I was able to create a very simple application that uses ActionScript to create a PrintDataGrid with some of the same properties as the display DataGrid. Let’s take a look …

:: First the interface –

<mx:Panel title="Print DataGrid Example" height="75%" width="75%"
	paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10">

	<mx:DataGrid id="myDataGrid" dataProvider="{dgProvider}" width="100%" height="100%">
		<mx:columns>
			<mx:DataGridColumn dataField="Index"/>
			<mx:DataGridColumn dataField="Qty"/>
		</mx:columns>
	</mx:DataGrid>

	<mx:Button id="printDG" label="Print" click="doPrint();"/>
</mx:Panel>

What you see above is the visual interface for this app. It consists of a DataGrid contained within a Panel. The dataProvider and the doPrint() function is defined in the ActionScript shown below.

import mx.collections.ArrayCollection;
import mx.printing.FlexPrintJob;
import mx.printing.PrintDataGrid;

I’m going to break-up the ActionScript into small chunks and explain.

The ArrayCollection is used to hold the DataGrid’s dataProvider. The FlexPrintJob and the PrintDataGrid classes are used to allow printing DataGrid components from within Flex.

[Bindable]public var dgProvider:ArrayCollection;
public var prodIndex:Number;

private var myPrintDataGrid:PrintDataGrid;
private var myPrintJob:FlexPrintJob;

I define the ArrayCollection instance that will hold the DataGrid’s data and a variable used in the creation of the DataGrid data. I also define a variable for the PrintDataGrid and FlexPrintJob class.

public function initData():void {
	// Create the data provider for the DataGrid control.
	dgProvider = new ArrayCollection;

	prodIndex=1;
	dgProvider.removeAll();
	for (var z:int=0; z<40; z++) {
		var prod1:Object = {};
		prod1.Qty = prodIndex * 7;
		prod1.Index = prodIndex++;
		dgProvider.addItem(prod1);
	}
}

On the creationComplete event the Application calls the initData function. The purpose of this function is to dynamically create a set of data for the ArrayCollection. Nothing special yet.

public function doPrint():void {
	myPrintJob = new FlexPrintJob();

	if (myPrintJob.start()) {
		myPrintDataGrid = new PrintDataGrid();

		//Set the print view properties.
		myPrintDataGrid.width = myPrintJob.pageWidth;
		myPrintDataGrid.height = myPrintJob.pageHeight;

		// Set the data provider of the FormPrintView component's data grid
		// to be the data provider of the displayed data grid.
		myPrintDataGrid.dataProvider = myDataGrid.dataProvider;

		myPrintDataGrid.visible = false;
		myPrintDataGrid.includeInLayout = false;
		Application.application.addChild(myPrintDataGrid);

		if(!myPrintDataGrid.validNextPage) {
			myPrintJob.addObject(myPrintDataGrid);
		} else {
			myPrintJob.addObject(myPrintDataGrid);

			while(true) {
				// Move the next page of data to the top of the print grid.
				myPrintDataGrid.nextPage();

				if(!myPrintDataGrid.validNextPage) {
					// This is the last page; queue it and exit the print loop.
					myPrintJob.addObject(myPrintDataGrid);

					break;
				} else {
					myPrintJob.addObject(myPrintDataGrid);
				}
			}

		}
		Application.application.removeChild(myPrintDataGrid);

		myPrintJob.send();
	}
}

Ok. Let’s boogie. The doPrint() function is where I do all the work. First I create an instance of the FlexPrintJob and use the start method to display the Print dialog box. Should the user click on the OK button the start method returns true.

Next I create a PrintDataGrid instance and set the width and height of the myPrintDataGrid instance to match the width and height of the page set in the Print dialog.

Now I set the dataProvider of myPrintDataGrid instance to match the dataProvider of the visual DataGrid.

So that myPrintDataGrid does not become visible, I set the visible property to false. So that myPrintDataGrid does not take up space in the application layout, I set the includeInLayout property to false. Then I add myPrintDataGrid to the display (it’s just invisible and does not take up space).

Now I’m ready to start printing. The validNextPage property is used to determine if data exists past the viewable area in the PrintDataGrid. Yes, I mean the viewable area of the invisible PrintDataGrid (huh? – stay with me) . Imagine if the DataGrid contains 100 rows of data but the maximum viewable area of the PrintDataGrid only show 50. The validNextPage property will return true. So I use the addObject method of the FlexPrintJob class to send the first 50 rows of data to the printer. I then enter into a While loop to first go to the nextPage and then check to see if there are more rows of data using the validNextPage property.

Once the validNextPage property returns false then we are on the last page. Each of the pages have been sent to the print queue.

After removing myPrintDataGrid from the Application’s display list we can finally send the print jobs to the printer – using the send method of the myPrintJob instance.

And there you have it. I created one DataGrid component that can be used as a display object and print object. I can make one change to the visual DataGrid and not worry about duplicating that change on another PrintDataGrid component.

Comments
  1. Esiminda Henry says:

    Please help! i have a problem of printing my datagrid data in multiple pages. I have try your code but problem still remains

  2. udayms says:

    Esiminda,
    Try out the CGrid component, it has printing built-in, am not sure if it would suite ur needs. But, check it out. It may work for you :).

    CGrid component Post –

    CustomGrid v1.0 (or SearchGrid v2.0)

    CGrid component Demo –
    http://udayms.com/flex/cgrid/UseCustomGrid.html

    Cheers,
    Uday M. Shankar
    http://flexed.wordpress.com

  3. Nice blog I will recommend you to all my friends. Thank you.

  4. scuty says:

    addObject does not exist in FlexPrintJob!

    How did you manage to run this code? I am using Flex 3.

    myPrintJob.addObject(myPrintDataGrid);

  5. scuty says:

    sorry! I found an error in my project! discard my last post!

  6. william says:

    for some reason it prints my datagrid with the datafields as headers not the labels. also it disregards any formatting and squishes everything together.
    any ideas?

  7. Cornelia says:

    Hi, I have a small question (very big for me). How can I print two grids one after another: when the first grid is finished, the second one is added right after, not on a diffrent page. Thanks in advance! šŸ™‚

  8. QFDaniel says:

    Actually,good post. thx

  9. Flexicious says:

    Please look at our site – http://www.flexicious.com, where we have implemented print, preview and excel export in addition to a host of other features

Leave a comment