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.

  1. 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.
  2. 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.
  3. In the print function do the following
    1. Create an instance of the FlexPrintJob class (4)
    2. 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)
      1. Create an instance of the custom component that contains the content to print
      2. Add the custom component as a child of the application
      3. 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
      4. 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.
      5. 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
        1. Add the custom component to the FlexPrintJob by using the addObject method.
      6. Else if the validNextPage property is true (meaning the content of the PrintDataGrid spans more than one page) do the following
        1. 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.
        2. Use a loop with the boolean expression being the validNextPage property. If validNextPage is true do the following in the loop body
          1. Call the PrintDataGrid's nextPage method, which causes the PrintDataGrid to load the next set of rows.
          2. Add the custom component to the FlexPrintJob by using the addObject method
          3. Note we will repeat these steps until we have added to the FlexPrintJob each page and the validNextPage property is false
      7. After the loop do the following
        1. remove from the application the custom component
        2. 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

  1. Flex 3 Developer's Guide, Printing
  2. Flex 3 Developer's Guide, Printing Multipage Output
  3. Flex 3 Language Reference, PrintDataGrid
  4. Flex 3 Language Reference, FlexPrintJob
  5. Example Application, Printing A DataGrid That Spans Multiple Pages

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Your howto is good, and I could have had much use of it a couple of months ago when I was trying to figure this out for myself. However, I must say that since that I have come to realise that printing in Flex is a lost cause.

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.
# Posted By Theo | 4/12/08 5:04 AM
flex printing using high end graphics gonna be digital and vinyl sticker
# Posted By Elena | 5/18/08 1:21 AM
Nice Tutorial for understanding FlexPrintJob. Have a look at FlexReport on code.google.com Its also a nice api to have some printing out of Flex.
# Posted By Chetan Sachdev | 6/4/08 11:16 PM
The print comes out clearer if you set "printAsBitmap = false"


***************************************
// 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.
# Posted By George Kellogg | 6/27/08 6:45 AM
Has anyone been able to actually get vector output with the "printAsBitmap = false" flag? On OS x at least, the "print to file" pdfs I'm getting are bitmapped, and not vector. Our users want to be able to export and tweak this stuff in illustrator, so not being able to get scalable vector output is a big problem.
# Posted By Reinhard Engels | 8/6/08 8:24 AM
What If I have to Print dynamically generated Multiple datagrid where some datagrid has multiple page and some expands to single page? Please reply, It will help me a lot to generate report module.

Thanks in advance
# Posted By Sachin | 9/12/08 6:53 AM
Sachin - I've not done that so I don't have an answer for you.
# Posted By Bruce | 9/12/08 10:13 AM
I wonder that PrintAdvancedDataGrid have bug. When I debug my app by run only each code line, it can print my table but not stable, sometimes ok and sometimes print nothing. When I run normal, it always print white page. I check my printer and see the flash object pending to print is very large (> 10MB) so I think seem the app have no enough time to send object to printer. Are you meet the same problem? What do you think about it?
I use code to work with AdvancedDataGrid follow link http://livedocs.adobe.com/flex/3/html/help.html?co...
# Posted By hai anh | 2/9/09 10:58 PM
Quote: Add the custom component as a child of the application

Sorry for being dumb, but how do you add the component as a child?
# Posted By Flyer | 3/28/09 1:51 PM
Flyer - Open the example application (see references above) and then right click on the background area and select view source.

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...
# Posted By Bruce | 3/28/09 2:53 PM
I have a datagrid that is being populated with google map directions.
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
# Posted By YhwhDesign | 11/11/09 12:10 AM
Nice Job, but i see that when i click print, i cant select the pages Range, From: To --> in the OS Print Dialog, is that a Bug is Flex?? or do i need to specify the Range befor calling the OS Dialog???
Thank you.
# Posted By Jimmy | 11/11/09 2:59 AM
Hi there,
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!
# Posted By Al | 1/20/10 8:22 AM
Great Example Bruce!
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
# Posted By Ram | 3/31/10 10:14 AM
Ram - good question. Unfortunately, I don't know the answer. If you find out please post back here.
# Posted By Bruce | 3/31/10 11:41 AM
Hi there. i am using a print job similar to your component. i am getting a problem which exists in your example too, so I thought I'd let you know about it. If I click on print, then select Microsoft XPS Document Writer and then cancel before choosing the file name, the printable component will appear in the page as it is not removed. If I find a solution, I will let you know
# Posted By Chris | 1/9/11 5:25 PM
Hi,
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.
# Posted By sireesha | 1/30/12 2:04 AM
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. If I click on print, then select Microsoft XPS Document Writer and then cancel before choosing the file name, the printable component will appear in the page as it is not removed.
# Posted By leaflet printing | 3/12/13 4:27 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.002. Contact Blog Owner