Friday, October 31, 2008

Printing Flex Data Grids

One of the questions that I was asked at Colorado Software Summit 2008 after one of my three presentations of Applying Flash to Java: Flex and OpenLaszlo was if there is a way to print the contents of a DataGrid. In this blog entry, I demonstrate simple application of the Flex PrintDataGrid control for doing just that.

The PrintDataGrid control component and the closely related PrintAdvancedDataGrid control component are components meant for visualization only. While they each inherit properties and behaviors from their respective parent classes (DataGrid and AdvancedDataGrid), the print-specific classes should not use any functionality that is associated with user interaction. Note also that the print-specific child classes are in the mx.printing package while their parents are in the mx.controls package.

One of the particularly useful aspects of the Flex 3 Language Reference is that it often includes example code for the language items being described. When the Flex item being described is visual, this reference often includes an actual running instantiation of the example code via the Flash Player. Fortunately, this is true of the PrintDataGrid, which includes multiple examples and does include an actual running Flash-based rendering of the examples.

I am basing my example of using the PrintDataGrid on the DataGrid I previously used in the blog entry Communication Between Two Flex Applications. Here, on one file called SimplePrintDataGridExample.mxml, is the entire code listing demonstrating a basic use of PrintDataGrid.

SimplePrintDataGridExample.mxml


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
viewSourceURL="http://localhost:8080/Css2008FlashExamples/flex/SimpleDataGrid/SimplePrintDataGridExample.mxml">

<mx:Script>
<![CDATA[
import mx.controls.Alert;
import flash.printing.PrintJobOrientation;
import mx.printing.FlexPrintJob;
import mx.printing.FlexPrintJobScaleType;
import mx.printing.PrintDataGrid;

/**
* Prints contents of DataGrid in print-friendly format.
*
* <p>ADDITIONAL REFERENCES:</p>
* http://livedocs.adobe.com/flex/3/langref/mx/printing/FlexPrintJob.html<br />
* http://livedocs.adobe.com/flex/3/html/printing_3.html
*/
public function printDataGridContents():void
{
const printJob:FlexPrintJob = new FlexPrintJob();

if ( printJob.start() )
{
const printDataGrid:PrintDataGrid = new PrintDataGrid();
printDataGrid.width = printJob.pageWidth;
printDataGrid.height = printJob.pageHeight;
printDataGrid.columns = dataGrid.columns;
printDataGrid.dataProvider = presenters.copy();
printDataGrid.visible = false;
Application.application.addChild(printDataGrid);
while (printDataGrid.validNextPage)
{
printDataGrid.nextPage();
printJob.addObject(printDataGrid);
}
printJob.send();
Application.application.removeChild(printDataGrid);
}
}
]]>
</mx:Script>

<mx:XMLList id="presenters">
<presenter>
<lastname>Johnsson</lastname>
<firstname>Dan Bergh</firstname>
<organization>OmegaPoint AB</organization>
<url>http://softwaresummit.org/2008/speakers/johnsson.htm</url>
</presenter>
<presenter>
<lastname>Kaplan-Moss</lastname>
<firstname>Jacob</firstname>
<organization>Whiskey Media</organization>
<url>http://softwaresummit.org/2008/speakers/kaplan-moss.htm</url>
</presenter>
<presenter>
<lastname>Lan</lastname>
<firstname>Ikai</firstname>
<organization>LinkedIn</organization>
<url>http://softwaresummit.org/2008/speakers/lan.htm</url>
</presenter>
<presenter>
<lastname>Marx</lastname>
<firstname>Dustin</firstname>
<organization>Raytheon Company</organization>
<url>http://softwaresummit.org/2008/speakers/marx.htm</url>
</presenter>
<presenter>
<lastname>Morrill</lastname>
<firstname>Dan</firstname>
<organization>Google</organization>
<url>http://softwaresummit.org/2008/speakers/morrill.htm</url>
</presenter>
<presenter>
<lastname>Moskowitz</lastname>
<firstname>David</firstname>
<organization>Productivity Solutions, Inc.</organization>
<url>http://softwaresummit.org/2008/speakers/moskowitz.htm</url>
</presenter>
<presenter>
<lastname>Opstvedt</lastname>
<firstname>Hermod</firstname>
<organization>DnB NOR</organization>
<url>http://softwaresummit.org/2008/speakers/opstvedt.htm</url>
</presenter>
</mx:XMLList>

<mx:Panel id="mainPanel" width="75%"
title="CSS 2008 DataGrid Example">
<mx:DataGrid id="dataGrid"
width="100%" height="100%"
rowCount="5" dataProvider="{presenters}">
<mx:columns>
<mx:DataGridColumn dataField="lastname"
headerText="Last Name"
width="75" />
<mx:DataGridColumn dataField="firstname"
headerText="First Name"
width="75" />
<mx:DataGridColumn dataField="organization"
headerText="Organization"
width="100" />
<mx:DataGridColumn dataField="url"
headerText="CSS URL"
width="200" />
</mx:columns>
</mx:DataGrid>
<mx:Button click="printDataGridContents();" label="Print!" />
</mx:Panel>

</mx:Application>


The original DataGrid (the one intended for interaction and not for printing that is defined in MXML rather than in ActionScript) is essentially the same as the one I used in the Flex-to-Flex Communication blog entry. A button has been added in this example to kick off the ActionScript method printDataGridContents().

The ActionScript method that is invoked when the button is presssed only directly associate the original, interactive DataGrid with the PrintDataGrid to get column names for the PrintDataGrid. For the source data, the PrintDataGrid is associated (via dataProvider property) with the same XML data that backs the original, interactive grid. Because I don't want the PrintDataGrid affecting the original XML, I used the XMLList.copy() function.

This example also demonstrates how the width and height of the PrintDataGrid can be associated with the FlexPrintJob's width and height.

The following two screen snapshots demonstrate how the Flex application whose code is listed above appears when it is first started and when the Print! button is clicked.


Initial Appearance of SimplePrintDataGridExample



Print! Option Selected via Button Click



When a printer is selected, the print-out of this data looks like that shown in the next screen snapshot.


Printed Output



The Google Chrome web browser was used for all of the above screen snapshots. One of the positive features of Google Chrome is its Developer's "View source" capability. The regular "View Source" capability shows the MXML source code without any translation of the original text and is not very appealing. However, one can choose Develooer->View source on that unappealing display of source to see source with color coding and line numbers as shown in the next screen snapshot.


Google Chrome Display of Developer->View source




I had explicitly made source code available for this Flex application (a process I described in a previous blog entry) so it is nice to have that source code displayed with color coding and line numbers.


Printing from Flex/Flash is Not Without Challenges

In my example here, I depended on the user (me!) to choose to print out in "landscape" mode. Had I printed in "portrait" mode, not all grid information would have been printed. Jesse Warden has a blog entry Forcing Landscape Printing in Flex 2 and 3 that talks about some of the challenges associated with trying to print in landscape mode from Flex.

Even though FlexPrintJob is easy to use, printing from Flex (or more specifically from Flash) can still be tricky, especially when there are multiple pages involved. Some efforts to make this easier include FlexReport and Lin Lin: Tips for using PrintingJob in flex 1.5. Of course, printing has been a difficult issue for many fine programming languages.


Conclusion

The FlexPrintJob object and associated components intended specifically for printing make it possible with relatively few lines of code to print out Flex data. I have found that it does require some trial-and-error to get the printing where I want it. There are also issues of how the user attempts to print (using the web browers's Print icon or option rather than the Flex application provided print capability), but these can be at least partially handled via training and/or use of JavaScript to disable those browser print features. Also, another nice option is to mix Flex with DHTML and have the print support be implemented with a static HTML page created specifically for printing.

1 comment:

theo said...

Hi, I'm Cornelia. I have a small question (very big for me). How can I print two grids, so that the grids won't start on diffrent pages (this I can do), but one after another.
Thanks in advance :)