Search code examples
apache-flexactionscriptprintingadvanceddatagrid

Flex PrintAdvancedDataGrid need something similar to sizeToPage for columns


I have an AdvancedDataGrid that's pretty wide (lots of columns that need to be wide enough to read) that I need to print. The PrintAdvancedDataGrid.sizeToPage property adjusts the height of the grid so that page breaks only occur between rows.

I'm looking for something similar for columns.

Here's a test case (main program, FlexBuilder 4.5)

    <fx:Script>
        <![CDATA[
            import mx.printing.FlexPrintJob;
            import mx.printing.FlexPrintJobScaleType;

            protected function btnPrint_clickHandler(event:MouseEvent):void
            {
                doPrint();
            }
            private function doPrint():void {
                var printJob:FlexPrintJob = new FlexPrintJob();

                if (printJob.start()) {
                    printJob.printAsBitmap = false;

                    var thePrintView:PrintView = new PrintView();
                    thePrintView.includeInLayout = false;
                    addElement(thePrintView);

                    thePrintView.height = printJob.pageHeight;

                    thePrintView.myDataGrid.source = myGrid;

                    thePrintView.validateNow();

                    // This example doesn't have that many rows, 
                    // so I'm skipping the extra code to handle "multiple pages"
                    printJob.addObject(thePrintView, FlexPrintJobScaleType.NONE);

                    removeElement(thePrintView);
                }
                printJob.send();
            }
        ]]>
    </fx:Script>

    <fx:Declarations>
        <fx:Array id="data">
            <fx:Object c1="c1r1" c2="c2r1" c3="c3r1" c4="c4r1" c5="c5r1" c6="c6r1" c7="c7r1" c8="c8r1" c9="c9r1" c10="c10r1" />
            <fx:Object c1="c1r2" c2="c2r2" c3="c3r2" c4="c4r2" c5="c5r2" c6="c6r2" c7="c7r2" c8="c8r2" c9="c9r2" c10="c10r2" />
            <fx:Object c1="c1r3" c2="c2r3" c3="c3r3" c4="c4r3" c5="c5r3" c6="c6r3" c7="c7r3" c8="c8r3" c9="c9r3" c10="c10r3" />
            <fx:Object c1="c1r4" c2="c2r4" c3="c3r4" c4="c4r4" c5="c5r4" c6="c6r4" c7="c7r4" c8="c8r4" c9="c9r4" c10="c10r4" />
            <fx:Object c1="c1r5" c2="c2r5" c3="c3r5" c4="c4r5" c5="c5r5" c6="c6r5" c7="c7r5" c8="c8r5" c9="c9r5" c10="c10r5" />
            <fx:Object c1="c1r6" c2="c2r6" c3="c3r6" c4="c4r6" c5="c5r6" c6="c6r6" c7="c7r6" c8="c8r6" c9="c9r6" c10="c10r6" />
            <fx:Object c1="c1r7" c2="c2r7" c3="c3r7" c4="c4r7" c5="c5r7" c6="c6r7" c7="c7r7" c8="c8r7" c9="c9r7" c10="c10r7" />
            <fx:Object c1="c1r8" c2="c2r8" c3="c3r8" c4="c4r8" c5="c5r8" c6="c6r8" c7="c7r8" c8="c8r8" c9="c9r8" c10="c10r8" />
            <fx:Object c1="c1r9" c2="c2r9" c3="c3r9" c4="c4r9" c5="c5r9" c6="c6r9" c7="c7r9" c8="c8r9" c9="c9r9" c10="c10r9" />
            <fx:Object c1="c1r10" c2="c2r10" c3="c3r10" c4="c4r10" c5="c5r10" c6="c6r10" c7="c7r10" c8="c8r10" c9="c9r10" c10="c10r10" />
            <fx:Object c1="c1r11" c2="c2r11" c3="c3r11" c4="c4r11" c5="c5r11" c6="c6r11" c7="c7r11" c8="c8r11" c9="c9r11" c10="c10r11" />
            <fx:Object c1="c1r12" c2="c2r12" c3="c3r12" c4="c4r12" c5="c5r12" c6="c6r12" c7="c7r12" c8="c8r12" c9="c9r12" c10="c10r12" />
        </fx:Array>
    </fx:Declarations>

    <s:Button id="btnPrint" x="0" y="0" label="Print" click="btnPrint_clickHandler(event)"/>
    <mx:AdvancedDataGrid id="myGrid" top="30" dataProvider="{data}">
        <mx:columns>
            <mx:AdvancedDataGridColumn dataField="c1" width="200" />
            <mx:AdvancedDataGridColumn dataField="c2" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c3" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c4" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c5" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c6" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c7" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c8" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c9" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c10" width="200"/>
        </mx:columns>
    </mx:AdvancedDataGrid>
</s:WindowedApplication>

And here's the PrintView.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009" 
         xmlns:s="library://ns.adobe.com/flex/spark" 
         xmlns:mx="library://ns.adobe.com/flex/mx"
         backgroundColor="0xffffff">

    <!-- The sizeToPage property is true by default, so the last
    page has only as many grid rows as are needed for the data. -->
    <mx:PrintAdvancedDataGrid id="myDataGrid"  height="100%" horizontalCenter="0">
        <mx:columns>
            <mx:AdvancedDataGridColumn dataField="c1" width="200" />
            <mx:AdvancedDataGridColumn dataField="c2" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c3" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c4" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c5" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c6" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c7" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c8" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c9" width="200"/>
            <mx:AdvancedDataGridColumn dataField="c10" width="200"/>
        </mx:columns>
    </mx:PrintAdvancedDataGrid>
</mx:VBox>

When you run this and press the Print button, you'll see the grid printed across 4 pages. That's a good thing - in my real app, I need the grid that wide. My concern is that the page breaks are splitting columns in a very ugly way.

Thanks,

Dan


Solution

  • Here's a more generalized solution. In the production code the original grid gets columns added dynamically, so the previous answer won't work. Also, I don't need all those extra PrintView objects. (It's good to have one for headers & footers).

    Here's the main code:

        <fx:Script>
            <![CDATA[
                import mx.printing.FlexPrintJob;
                import mx.printing.FlexPrintJobScaleType;
                import mx.printing.PrintAdvancedDataGrid;
    
                protected function btnPrint_clickHandler(event:MouseEvent):void
                {
                    doPrint2();
                }
                private function doPrint2():void {
                    var printJob:FlexPrintJob = new FlexPrintJob();
    
                    if (printJob.start()) {
                        printJob.printAsBitmap = false;
    
                        var thePrintView:PrintView = new PrintView();
                        thePrintView.includeInLayout = false;
                        addElement(thePrintView);
                        thePrintView.height = printJob.pageHeight;
    
                        var columns:Array = new Array();
                        var colWidth:Number = 0;
                        for (var colIndex:int = 0; colIndex < myGrid.columns.length; colIndex++)
                        {
                            var aColumn:AdvancedDataGridColumn = myGrid.columns[colIndex] as AdvancedDataGridColumn;
                            if (colWidth + aColumn.width < printJob.pageWidth) {
                                columns.push(aColumn);
                                colWidth += aColumn.width;
                            } else {
                                thePrintView.grid.columns = columns;
                                thePrintView.grid.dataProvider = myGrid.dataProvider;
                                thePrintView.validateNow();
                                // This example doesn't have that many rows, 
                                // so I'm skipping the extra code to handle "multiple pages"
                                printJob.addObject(thePrintView, FlexPrintJobScaleType.NONE);
                                removeElement(thePrintView);
    
                                columns.length = 0;
                                columns.push(aColumn);
                                colWidth = aColumn.width;
    
                                thePrintView = new PrintView();
                                thePrintView.includeInLayout = false;
                                addElement(thePrintView);
                                thePrintView.height = printJob.pageHeight;
                            }
                        }
                        if (columns.length > 0)
                        {
                            thePrintView.grid.columns = columns;
                            thePrintView.grid.dataProvider = myGrid.dataProvider;
                            thePrintView.validateNow();
                            // This example doesn't have that many rows, 
                            // so I'm skipping the extra code to handle "multiple pages"
                            printJob.addObject(thePrintView, FlexPrintJobScaleType.NONE);
                            removeElement(thePrintView);
                        }
                    }
                    printJob.send();
                }
            ]]>
        </fx:Script>
    
        <fx:Declarations>
            <fx:Array id="data">
                <fx:Object c1="c1r1" c2="c2r1" c3="c3r1" c4="c4r1" c5="c5r1" c6="c6r1" c7="c7r1" c8="c8r1" c9="c9r1" c10="c10r1" />
                <fx:Object c1="c1r2" c2="c2r2" c3="c3r2" c4="c4r2" c5="c5r2" c6="c6r2" c7="c7r2" c8="c8r2" c9="c9r2" c10="c10r2" />
                <fx:Object c1="c1r3" c2="c2r3" c3="c3r3" c4="c4r3" c5="c5r3" c6="c6r3" c7="c7r3" c8="c8r3" c9="c9r3" c10="c10r3" />
                <fx:Object c1="c1r4" c2="c2r4" c3="c3r4" c4="c4r4" c5="c5r4" c6="c6r4" c7="c7r4" c8="c8r4" c9="c9r4" c10="c10r4" />
                <fx:Object c1="c1r5" c2="c2r5" c3="c3r5" c4="c4r5" c5="c5r5" c6="c6r5" c7="c7r5" c8="c8r5" c9="c9r5" c10="c10r5" />
                <fx:Object c1="c1r6" c2="c2r6" c3="c3r6" c4="c4r6" c5="c5r6" c6="c6r6" c7="c7r6" c8="c8r6" c9="c9r6" c10="c10r6" />
                <fx:Object c1="c1r7" c2="c2r7" c3="c3r7" c4="c4r7" c5="c5r7" c6="c6r7" c7="c7r7" c8="c8r7" c9="c9r7" c10="c10r7" />
                <fx:Object c1="c1r8" c2="c2r8" c3="c3r8" c4="c4r8" c5="c5r8" c6="c6r8" c7="c7r8" c8="c8r8" c9="c9r8" c10="c10r8" />
                <fx:Object c1="c1r9" c2="c2r9" c3="c3r9" c4="c4r9" c5="c5r9" c6="c6r9" c7="c7r9" c8="c8r9" c9="c9r9" c10="c10r9" />
                <fx:Object c1="c1r10" c2="c2r10" c3="c3r10" c4="c4r10" c5="c5r10" c6="c6r10" c7="c7r10" c8="c8r10" c9="c9r10" c10="c10r10" />
                <fx:Object c1="c1r11" c2="c2r11" c3="c3r11" c4="c4r11" c5="c5r11" c6="c6r11" c7="c7r11" c8="c8r11" c9="c9r11" c10="c10r11" />
                <fx:Object c1="c1r12" c2="c2r12" c3="c3r12" c4="c4r12" c5="c5r12" c6="c6r12" c7="c7r12" c8="c8r12" c9="c9r12" c10="c10r12" />
            </fx:Array>
        </fx:Declarations>
    
        <s:Button id="btnPrint" x="0" y="0" label="Print" click="btnPrint_clickHandler(event)"/>
        <mx:AdvancedDataGrid id="myGrid" top="30" dataProvider="{data}">
            <mx:columns>
                <mx:AdvancedDataGridColumn dataField="c1" width="200" />
                <mx:AdvancedDataGridColumn dataField="c2" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c3" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c4" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c5" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c6" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c7" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c8" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c9" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c10" width="200"/>
            </mx:columns>
        </mx:AdvancedDataGrid>
    </s:WindowedApplication>
    

    The PrintView is as before. The actual column definitions are irrelevant.

        <!-- The sizeToPage property is true by default, so the last
        page has only as many grid rows as are needed for the data. -->
        <mx:PrintAdvancedDataGrid id="grid"  height="100%" horizontalCenter="0">
            <mx:columns>
                <mx:AdvancedDataGridColumn dataField="c1" width="200" />
                <mx:AdvancedDataGridColumn dataField="c2" width="200"/>
                <mx:AdvancedDataGridColumn dataField="c3" width="200"/>
            </mx:columns>
        </mx:PrintAdvancedDataGrid>
    </mx:VBox>
    

    I hope this helps someone else.