Flex - Printing A DataGrid That Spans Multiple Printed Pages
Introduction
I recently needed to add a print capability to a Flex application to allow the user to print the results being displayed in a DataGrid control. The print out would need to span multiple pages since the number of rows displayed in the DataGrid exceeds the height of one printed page. Not having had to print a DataGrid's content before I consulted the Flex 3 documentation. The developer's guide (1,2) provides a good explanation of how to print (1) and shows an example of how to print a DataGrid that will span multiple pages (2). However, the multipage example (2) is a bit complex, has some convoluted logic (uses an endless loop) and is hard to follow since it makes use of several custom components to provide a header and footer to the printed pages. So I thought a simpler example and explanation of just printing the DataGrid on multiple pages might be beneficial.
Flex 3 provides the FlexPrintJob class to enable printing (1,3). In pseudo-code you need to do the following to print the DataGrid's contents over multiple pages.
- Create a custom component that will contain the content to print. Use the PrintDataGrid control (3) instead of the normal DataGrid control in this custom component.
- Create a button the user can click to print. Have the button's click event call a function that will contain the code to print the output.
- In the print function do the following
- Create an instance of the FlexPrintJob class (4)
- If calling the FlexPrintJob's start method returns true do the following
(note when the user clicks on OK in the print dialog window, the start method will return true, if the user clicks on cancel in the print dialog window, the start method returns false)
- Create an instance of the custom component that contains the content to print
- Add the custom component as a child of the application
- Set the height and width of the custom component to match the printed page's printable area height and width by using FlexPrintJob's pageWidth and pageHeight public properties
- Set the PrintDataGrid control's dataProvider to equal the dataProvider of the DataGrid that is being viewed. Now the content of the PrintDataGrid control that is contained by the custom component that will be printed has the same data as the DataGrid being viewed by the user. Note that when you create the PrintDataGrid control you should specify specific width's for each column that will not exceed the width of the printed page.
- The PrintDataGrid has a validNextPage property that is true or false. If this property is true, the PrintDataGrid control has more rows then are currently displayed. So if this property is true, there is another page of PrintDataGrid content to print. Wrap this property in an if statement and if it equals false (meaning the content of the PrintDataGrid can fit on just one page) then do the following
- Add the custom component to the FlexPrintJob by using the addObject method.
- Else if the validNextPage property is true (meaning the content of the PrintDataGrid spans more than one page) do the following
- Add the custom component to the FlexPrintJob by using the addObject method. This gets the first page of the custom component set for printing. Each call to addObject will setup a new page to print.
- Use a loop with the boolean expression being the validNextPage property. If validNextPage is true do the following in the loop body
- Call the PrintDataGrid's nextPage method, which causes the PrintDataGrid to load the next set of rows.
- Add the custom component to the FlexPrintJob by using the addObject method
- Note we will repeat these steps until we have added to the FlexPrintJob each page and the validNextPage property is false
- After the loop do the following
- remove from the application the custom component
- Call the FlexPrintJob's send method. Each object added to the FlexPrintJob is now sent to the printer.
If you follow the pseudo-code above while viewing the source code in my example application (5) it should be clear how each step above is executed in the code. The example application reads in an XML file, converts the XML to an XMLListCollection, and uses the XMLListCollection as the data provider for a DataGrid control. The example application has a custom component based upon a VBox control. All that is contained in the VBox control is a PrintDataGrid control. When viewing the example, just right-click on it to see the source code.
Summary
I hope the combination of the pseudo-code, the example application, and the references below will make it easier for you to understand how to print the contents of a DataGrid that spans multiple pages. The hard part for me was initially understanding the flow of instructions in the print function. Once you've mastered this simple example, you can better understand the more complex example shown in the Flex 3 Developer's Guide (2), which includes custom components to add a header and footer to each page (and even logic that controls whether or not the header and footer are displayed).
Special Note
If you examine the printed output, you may notice the last row on the first printed page displays just part of the title. This seems to be caused when the title displayed in the last row spans more then one line. I'm researching how to fix this issue and will post an update once I figure it out. If you know how to fix this issue then please post a comment.
References
- Flex 3 Developer's Guide, Printing
- Flex 3 Developer's Guide, Printing Multipage Output
- Flex 3 Language Reference, PrintDataGrid
- Flex 3 Language Reference, FlexPrintJob
- Example Application, Printing A DataGrid That Spans Multiple Pages
Why? The quality is really, really bad. Type comes out blurry as hell, it looks like it was created at a half or quarter screen resolution and then scaled up before printing. You would expect Flash/Flex, which is resolution independent, to do this better.
I've since scrapped any plans for printing directly from Flex and instead I generate PDF:s on the server side. Most of the time it's actually less work and it's always much better quality. It requires a good PDF library on the backend though.
***************************************
// Create an instance of the FlexPrintJob class.
var printJob:FlexPrintJob = new FlexPrintJob();
// Print as vector - GK
printJob.printAsBitmap = false;
***************************************
From the Adobe® Flex™ 3 Language Reference:
printAsBitmap property
printAsBitmap:Boolean [read-write]
Specifies whether to print the job content as a bitmap (true) or in vector format (false). Printing as a bitmap supports output that includes a bitmap image with alpha transparency or color effects. If the content does not include any bitmap images with alpha transparency or color effects, you can print in higher quality vector format by setting the printAsBitmap property to false.
The default value is true.
Thanks in advance
I use code to work with AdvancedDataGrid follow link http://livedocs.adobe.com/flex/3/html/help.html?co...
Sorry for being dumb, but how do you add the component as a child?
Read the function doPrint and you'll find the addChild command. You can learn more about the addChild command in the Flex 3 reference: http://livedocs.adobe.com/flex/3/html/help.html?co...
the results that are returned into that datagrid have to have the itemrender="{HTMLRenderer}" tag so that the html code that makes the font bold from google is shown correctly.
i tired to enter that small snipet of code into the myprintview.mxml file and it said that it is not correct basically it will not let me use that in that file. so my question is how would i get it to not print the <b> </b> (html) tags.
thanks
great tut
Thank you.
Thanks for the great post. I wonder, did you ever find a fix for the variable row special note you mentioned? This is the fact that when you print and there is one row that is more than the others than the bottom rows are messed up...
thanks!
The example on Adobe adds lot of confusion
This works fine with the number of rows exceeding the height of the page so far so good.
What if i have 30 columns in my grid,which would obviously not fit in one page
need your expertise please
Thanks
Ram
Nice example its saved my time.i amfacing one issue while using this code in multiple pages case
while loop is not getting terminated(validnextpage is returning true everytime)
pls suggest me any solution for this.
Thanks in Advance.