Reputation: 187499
I'd like to show/hide a column at runtime based on a particular condition. I'm using "Print when expression" to conditionally show/hide this column (and it's header) in my report. When the column is hidden, the space it would have occupied is left blank, which is not particularly attractive.
I would prefer if the extra space was used in a more effective manner, possibilities include:
In theory, I could achieve the first by setting the width of the column (and header) to 0, but also indicate that the column should resize to fit its contents. But JasperReports does not provide a "resize width to fit contents" option.
Another possibility is to generate reports using the Jasper API instead of defining the report template in XML. But that seems like a lot of effort for such a simple requirement.
Upvotes: 11
Views: 30563
Reputation: 21710
In later version (v5 or above) of jasper reports you can use the jr:table
component and truly achieve this (without the use of java code as using dynamic-jasper or dynamic-reports).
The method is using a <printWhenExpression/>
under the <jr:column/>
Sample Data
+----------------+--------+
| User | Rep |
+----------------+--------+
| Jon Skeet | 854503 |
| Darin Dimitrov | 652133 |
| BalusC | 639753 |
| Hans Passant | 616871 |
| Me | 6487 |
+----------------+--------+
Sample jrxml
Note: the parameter $P{displayRecordNumber}
and the <printWhenExpression>
under first jr:column
<?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="reputation" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="a88bd694-4f90-41fc-84d0-002b90b2d73e">
<style name="table">
<box>
<pen lineWidth="1.0" lineColor="#000000"/>
</box>
</style>
<style name="table_TH" mode="Opaque" backcolor="#F0F8FF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<style name="table_CH" mode="Opaque" backcolor="#BFE1FF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<style name="table_TD" mode="Opaque" backcolor="#FFFFFF">
<box>
<pen lineWidth="0.5" lineColor="#000000"/>
</box>
</style>
<subDataset name="tableDataset" uuid="7a53770f-0350-4a73-bfc1-48a5f6386594">
<field name="User" class="java.lang.String"/>
<field name="Rep" class="java.math.BigDecimal"/>
</subDataset>
<parameter name="displayRecordNumber" class="java.lang.Boolean">
<defaultValueExpression><![CDATA[true]]></defaultValueExpression>
</parameter>
<queryString>
<![CDATA[]]>
</queryString>
<title>
<band height="50">
<componentElement>
<reportElement key="table" style="table" x="0" y="0" width="555" height="47" uuid="76ab08c6-e757-4785-a43d-b65ad4ab1dd5"/>
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
<datasetRun subDataset="tableDataset" uuid="07e5f1c2-af7f-4373-b653-c127c47c9fa4">
<dataSourceExpression><![CDATA[$P{REPORT_DATA_SOURCE}]]></dataSourceExpression>
</datasetRun>
<jr:column width="90" uuid="918270fe-25c8-4a9b-a872-91299cddbc31">
<printWhenExpression><![CDATA[$P{displayRecordNumber}]]></printWhenExpression>
<jr:columnHeader style="table_CH" height="30" rowSpan="1">
<staticText>
<reportElement x="0" y="0" width="90" height="30" uuid="5cd6da41-01d5-4f74-99c2-06784f891d1e"/>
<textElement textAlignment="Center" verticalAlignment="Middle"/>
<text><![CDATA[Record number]]></text>
</staticText>
</jr:columnHeader>
<jr:detailCell style="table_TD" height="30" rowSpan="1">
<textField>
<reportElement x="0" y="0" width="90" height="30" uuid="5fe48359-0e7e-44b2-93ac-f55404189832"/>
<textElement textAlignment="Center" verticalAlignment="Middle"/>
<textFieldExpression><![CDATA[$V{REPORT_COUNT}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
<jr:column width="90" uuid="7979d8a2-4e3c-42a7-9ff9-86f8e0b164bc">
<jr:columnHeader style="table_CH" height="30" rowSpan="1">
<staticText>
<reportElement x="0" y="0" width="90" height="30" uuid="61d5f1b6-7677-4511-a10c-1fb8a56a4b2a"/>
<textElement textAlignment="Center" verticalAlignment="Middle"/>
<text><![CDATA[Username]]></text>
</staticText>
</jr:columnHeader>
<jr:detailCell style="table_TD" height="30" rowSpan="1">
<textField>
<reportElement x="0" y="0" width="90" height="30" uuid="a3cdb99d-3bf6-4c66-b50c-259b9aabfaef"/>
<box leftPadding="3" rightPadding="3"/>
<textElement verticalAlignment="Middle"/>
<textFieldExpression><![CDATA[$F{User}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
<jr:column width="90" uuid="625e4e5e-5057-4eab-b4a9-c5b22844d25c">
<jr:columnHeader style="table_CH" height="30" rowSpan="1">
<staticText>
<reportElement x="0" y="0" width="90" height="30" uuid="e1c07cb8-a44c-4a8d-8566-5c86d6671282"/>
<textElement textAlignment="Center" verticalAlignment="Middle"/>
<text><![CDATA[Reputation]]></text>
</staticText>
</jr:columnHeader>
<jr:detailCell style="table_TD" height="30" rowSpan="1">
<textField pattern="#,##0">
<reportElement x="0" y="0" width="90" height="30" uuid="6be2d79f-be82-4c7b-afd9-0039fb8b3189"/>
<box leftPadding="3" rightPadding="3"/>
<textElement textAlignment="Right" verticalAlignment="Middle"/>
<textFieldExpression><![CDATA[$F{Rep}]]></textFieldExpression>
</textField>
</jr:detailCell>
</jr:column>
</jr:table>
</componentElement>
</band>
</title>
</jasperReport>
Output with $P{displayRecordNumber}=true
Output with $P{displayRecordNumber}=false
As you can see the columns adapts nicely on the basis of which are displayed.
Upvotes: 14
Reputation: 1453
JasperDesign is used to modify the template object (JasperReport) from within the code at runtime. I guess this might fit in your case.
Upvotes: 4
Reputation: 1714
I guess this answer comes way too late, but I add it for the record. In my case I could solve it without any additional dependencies or tools. In the JRXML file, I just added the textfields width a dynamic width multiple times. Once per possible width that is. Then on each textfield, I have set that it should only be printed in case of a certain condition.
This might not be as elegant as setting the width dynamically, but it does the trick without any hassle with extra libraries.
Upvotes: 0
Reputation: 11
I recommend to use DynamicReports, it's open source and based on JasperReports. The main benefit of this library is a dynamic report design and no need for a visual report designer.
Upvotes: 1
Reputation: 21
Remove line when blank: This option takes away the vertical space occupied by an object, if it is not visible; the element visibility is determined by the value of the expression contained in the Print when expression attribute. Think of the page as a grid where the elements are placed, with a line being the space the element occupies. Figure 4-17 highlights the element A line; in order to really remove this line, all the elements that share a portion of the line have to be null (that is, they will not be printed).
Upvotes: 2
Reputation: 16931
Check THIS In that tutorial they are using XML template with Velocity framework. This is pretty complex. And to make it simpler you can us DynamicJasper. This library is an open source Java API that works over JasperReports that solves the dynamic columns issue.
Upvotes: 0
Reputation: 1738
A slight variation on the "second report" theme that I have used is to isolate the part of the report where you have an optional column into it's own subreport, and then create two subreports, one with and one without the column, and then use conditions to determine which subreport to print.
Upvotes: 1
Reputation: 14192
If it is just one column, is it possible to place this column to the far right, and then use the print when expression. That way there is not a hole in the middle. I know this is not ideal, as I had tried to do what you are currently trying to accomplish in the past, and could not find what I call a good solution.
A second idea would to be create a second report based on the first with out the column, and then when calling the report check the condition, to decide which one to call. Again not ideal, but would work.
I know this is not really the answer you were looking for, but one of these suggestions may work for you.
Upvotes: 0