springcorn
springcorn

Reputation: 631

Print footer on first page only

I would like to have a footer appear only on the first page of jasper reports.

After searching the forums, I have seen this question asked and improperly answered several times here. As many have suggested I have tried putting a print when expression on the footer band to prevent it from printing when it isn't the first page like:

new Boolean($V{PAGE_NUMBER}.intValue() == 1)

This does not work though. The result is that none of the attributes of the page footer print, but the footer block still prints and takes up space preventing the detail from using the whole page. Effectively, you have a footer with data on the first page and a footer with no data on every following page.

Does anyone know a trick how to actually make this work?

Upvotes: 11

Views: 15052

Answers (4)

talex
talex

Reputation: 20464

Unfortunately @emecheon answer doesn't work with current jasper version ( I use 6.7.0), but cure is pretty much the same.

I change columnFooterOffsetY after first page.

This way you can have footer of different size for each page.

public class CustomVerticalFiller extends JRVerticalFiller {

    private int pageNumber = 0;

    public CustomVerticalFiller(JasperReportsContext jasperReportsContext, JasperReport jasperReport) throws JRException {
        super(jasperReportsContext, jasperReport);
    }


    @Override
    protected void addPage(JRPrintPage page) {
        super.addPage(page);
        pageNumber++;
        if (pageNumber == 2) {
            columnFooterOffsetY += pageFooter.getHeight();
        }
    }
}

Upvotes: 3

emecheon
emecheon

Reputation: 309

Definitely there does not seem to be a direct way of achieving it, at least with current version of Jasper libraries available. However here's a very crude workaround that worked for us in a similar requirement. I separated out only the footer management part of the code into a sample project this morning and it works fine.

Notes:

  • Not sure if this works with complex reports (especially if column-footer needs to be printed, as we manually modify the columnFooterOffsetY value). We had to generate a simple report with only title, detail and footer bands.
  • Importantly, i do not recommend using this solution for complex requirements as it may induce maintainability issues in long run (especially if you migrate to a later version of jasperreports library in future which might have modified the report-filling logic).
  • I have used JasperReports library version 5.0.0 for the testing.

How the example is built:

  • Created JRXML with iReport, with a printwhenexpression, new Boolean($V{PAGE_NUMBER}.intValue() == 1, for the page-footer band.
  • Created a Custom report-filler instance, extending the JRVerticalFiller class.

Sample source XML used: (add additional lines to the XML so that the report wraps to multiple pages)

<?xml version="1.0" encoding="UTF-8"?>

<employees>
    <employee id="1001" name="AAA" email="[email protected]" salary="20500.125"/>
    <employee id="1002" name="BBB" email="[email protected]" salary="10000.500"/>
    <employee id="1003" name="CCC" email="[email protected]" salary="12275.750"/>
    <employee id="1004" name="DDD" email="[email protected]" salary="10750.750"/>
</employees>

JRXML created with iReport (with a printwhenexpression for the footer band):

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="jr_footer_display_test" pageWidth="792" pageHeight="288" orientation="Landscape" columnWidth="752" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="27ac3ae2-27da-484b-b088-b4d79aa973cc">
    <property name="ireport.zoom" value="1.0"/>
    <property name="ireport.x" value="0"/>
    <property name="ireport.y" value="0"/>
    <queryString language="xPath">
        <![CDATA[//employee]]>
    </queryString>
    <field name="email" class="java.lang.String">
        <fieldDescription><![CDATA[./@email]]></fieldDescription>
    </field>
    <field name="id" class="java.lang.String">
        <fieldDescription><![CDATA[./@id]]></fieldDescription>
    </field>
    <field name="name" class="java.lang.String">
        <fieldDescription><![CDATA[./@name]]></fieldDescription>
    </field>
    <field name="salary" class="java.lang.String">
        <fieldDescription><![CDATA[./@salary]]></fieldDescription>
    </field>
    <background>
        <band splitType="Stretch"/>
    </background>
    <columnHeader>
        <band height="50">
            <staticText>
                <reportElement uuid="c3d42e71-672e-402f-9fbb-4889be2a269b" x="29" y="2" width="100" height="20"/>
                <textElement/>
                <text><![CDATA[ID]]></text>
            </staticText>
            <staticText>
                <reportElement uuid="a4c42dc4-4276-485a-b5a6-b4e6bd2bc217" x="136" y="2" width="100" height="20"/>
                <textElement/>
                <text><![CDATA[Name]]></text>
            </staticText>
            <staticText>
                <reportElement uuid="157e527b-7ad5-46bf-a06d-2fa0a2686b1e" x="253" y="2" width="100" height="20"/>
                <textElement/>
                <text><![CDATA[Email]]></text>
            </staticText>
            <staticText>
                <reportElement uuid="4d87c542-7057-4bc1-9a7e-fbd6a554f33a" x="386" y="2" width="100" height="20"/>
                <textElement/>
                <text><![CDATA[Salary]]></text>
            </staticText>
        </band>
    </columnHeader>
    <detail>
        <band height="21" splitType="Stretch">
            <textField>
                <reportElement uuid="31d09543-a128-469a-be38-3d8987ba781b" x="29" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression><![CDATA[$F{id}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement uuid="ce5c11f8-68da-4efd-93fa-e1f1b5ce407f" x="136" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement uuid="300dcc3b-8a2a-489d-8518-7283c95b2f88" x="253" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression><![CDATA[$F{email}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement uuid="a37f2df9-2459-446d-bc47-488a336aa60e" x="386" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression><![CDATA[$F{salary}]]></textFieldExpression>
            </textField>
        </band>
    </detail>
    <pageFooter>
        <band height="40" splitType="Stretch">
        <printWhenExpression><![CDATA[new Boolean($V{PAGE_NUMBER}.intValue() == 1)]]></printWhenExpression>
            <textField>
                <reportElement uuid="3d9beff7-69b8-44d9-af80-2962b9262368" x="29" y="12" width="80" height="20"/>
                <textElement textAlignment="Left"/>
                <textFieldExpression><![CDATA["Page: "+$V{PAGE_NUMBER}]]></textFieldExpression>
            </textField>
        </band>
    </pageFooter>
</jasperReport>

Custom report-filler implementation: (this handles the height resetting logic to ensure detail band stretches longer from page 2 onwards)

public class CustomVerticalFiller extends JRVerticalFiller {

    private JRFillBand detailBand = null;

    private int pageNumber = -1;

    protected CustomVerticalFiller(JasperReportsContext jasperReportsContext, JasperReport jasperReport) throws JRException {
        super(jasperReportsContext, jasperReport);

        detailBand = detailSection.getFillBands()[0];
    }

    // this method gets called after each detail band row is filled
    protected void resolveBandBoundElements(JRFillBand band, byte evaluation) throws JRException {
        if(band == detailBand) {
            if((detailBand.getBreakHeight() > columnFooterOffsetY - offsetY) && (columnIndex == columnCount - 1)) {
                // we have reached end of a page

                pageNumber++;

                // we reset the offset when we are at the end of page 2, so that jasper continues to fill data
                if(pageNumber == 1) {
                    columnFooterOffsetY += pageFooter.getHeight();
                }
            }
        }
    }
}

And the Java code that actually uses the custom filler to export a PDF:

InputStream inputStream = new FileInputStream(new File(<my jrxml file path>));

JRDataSource dataSource = new JRXmlDataSource(new File(<my source xml file path>), "//employee");

Map parameters = new HashMap();

JasperDesign jasperDesign = JRXmlLoader.load(inputStream);
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);

CustomVerticalFiller customVerticalFiller = new CustomVerticalFiller(DefaultJasperReportsContext.getInstance(), jasperReport);
JasperPrint jasperPrint = customVerticalFiller.fill(parameters, dataSource);

JasperExportManager.exportReportToPdfFile(jasperPrint, <target pdf file path>);

Upvotes: 6

Unknown
Unknown

Reputation: 119

The expression I use to print a footer only on the first page is the following:
In the Print When Expression field

IF($V{PAGE_NUMBER}.intValue()==1,TRUE( ),FALSE( ))

It checks whether this is the first page and if so it returns true and prints the band. If not, it does not print anything.

If you would like to print one footer on the first page and a different one on the following pages. I use this code as the expression for the subreport properties. (not print when expression)

IF($V{PAGE_NUMBER}.intValue()==1,"subreportFooter1.jasper","subreportFooter2.jasper")

Upvotes: 0

Murugans
Murugans

Reputation: 51

You should put this code on Band Properties Print when expression of PageFooter

new Boolean( $V{PAGE_NUMBER}.intValue() == 1 )

Upvotes: 3

Related Questions