I want to make text in the textValue to be red when the numeric value of the cell is less than zero. Currently my configuration is like this:
<style name="RedText">
<conditionalStyle>
<conditionExpression><![CDATA[$F{col1}.compareTo(BigDecimal.ZERO) == -1]]></conditionExpression>
<style forecolor="#FF0000"/>
</conditionalStyle>
</style>
I have more cells (col2, col3, col4 ...) that I would need to apply this red text style. Is it possible to make it universal for current value, etc. col*?
The standard/classical way without using Java code
It is impossible without using Java code. In your case you need to create the new style for each field and apply this concrete style for textField element with conditionExpression contains the value of concrete field.
In common case the expression of textField can be complex, the same is true for the conditionExpression. The style does not know to which control it belongs. We can't operate with value of abstract field (parameter/variable), the engine need the concrete names to calculate expression.
Using Java API
Is it possible to solve the task applying style with JasperReports Java API. For example:
JRDesignStyle boldStyle = new JRDesignStyle();
boldStyle.setName("Sans_Bold");
boldStyle.setFontName("DejaVu Sans");
boldStyle.setFontSize(12);
boldStyle.setBold(true);
// ...
textField.setStyle(boldStyle);
JRDesignExpression expression = new JRDesignExpression();
expression.setText("$F{col1}");
textField.setExpression(expression);
Using backdoor or "yes we like to hack"
Look at the beatiful class in Java is Map, it so invaluable in JasperReports. It can help us to crack this task.
- We need parameter of Map type for storing the value of field (it will be abstract field - "coln")
- We need to enable applying style during resolving expression of a textField. The propery
net.sf.jasperreports.style.evaluation.time.enabled will help to enable this feature.
- We need some Java method for putting value in to the Map (as a storage of a "coln") which returns the value we just put. The Map.put(K key, V value) is not good for this purpose. I wrote the small Utility class with wrapper over Map.put method.
The datasouce
The using of simple csv datasource is enough for this example. I like this kind of datasource for testing and debugging.
col1,col2,col3,col4,col5
1,2,3,9,-5
-2,6,-3,4,1
2,-2,-2,7,-3
8,3,4,-5,6
The name of data adapter for this datasource in the example below is numbers.csv. The first line from the file is skipped - it is contains the column's name.
Java code
It is a very simple utility class
public class Storage {
public static Integer add(Map<String, Integer> map, String key, Integer value) {
map.put(key, value);
return value;
}
}
Report template
The import for our utitlity class should be added for using it.
For correct resolving expression of conditional style we need to use in expression some parameter or some variable (you can check the source code of JasperReports). I'll add some fake variable for using in conditionExpression
We need to put the value of "coln" to the Map and then use this value in conditional style. In this case we don't need to know the name of field we are checking in conditional style. The parameter will be used for storing Map.
We need place and draw the value of "coln" in two runs. We can use fake invisible textField to put the field's value to the Map and another textField to show value with applying conditional style. The positions and sizes of this textFields are same - one above the other.
Our condition will be like this:
<style name="ColoredText">
<conditionalStyle>
<conditionExpression><![CDATA[(((Integer)$P{STORAGE}.get($P{KEY})) < 0)]]></conditionExpression>
<style forecolor="blue"/>
</conditionalStyle>
<conditionalStyle>
<conditionExpression><![CDATA[(((Integer)$P{STORAGE}.get($P{KEY})) > 0)]]></conditionExpression>
<style forecolor="green"/>
</conditionalStyle>
</style>
There is no field in conditionExpression and it works :)
The jrxml file:
<?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="Apply style withou name" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="numbers.csv"/>
<property name="net.sf.jasperreports.style.evaluation.time.enabled" value="true"/>
<import value="some.package.Storage"/>
<style name="ColoredText">
<conditionalStyle>
<conditionExpression><![CDATA[$P{STORAGE}.get($P{KEY}) == null && !"null".equalsIgnoreCase($V{FAKE})]]></conditionExpression>
<style forecolor="#CC0000"/>
</conditionalStyle>
<conditionalStyle>
<conditionExpression><![CDATA[(((Integer)$P{STORAGE}.get($P{KEY})) < 0) && !"null".equalsIgnoreCase($V{FAKE})]]></conditionExpression>
<style forecolor="#0037FF"/>
</conditionalStyle>
<conditionalStyle>
<conditionExpression><![CDATA[(((Integer)$P{STORAGE}.get($P{KEY})) > 0) && !"null".equalsIgnoreCase($V{FAKE})]]></conditionExpression>
<style forecolor="#00BA00"/>
</conditionalStyle>
</style>
<style name="Fake">
<conditionalStyle>
<conditionExpression><![CDATA[!"null".equalsIgnoreCase($V{FAKE})]]></conditionExpression>
<style mode="Opaque" forecolor="#FFFFFF" backcolor="#FFFFFF"/>
</conditionalStyle>
</style>
<parameter name="STORAGE" class="java.util.Map">
<defaultValueExpression><![CDATA[new java.util.HashMap()]]></defaultValueExpression>
</parameter>
<parameter name="KEY" class="java.lang.String">
<defaultValueExpression><![CDATA["key"]]></defaultValueExpression>
</parameter>
<field name="col1" class="java.lang.Integer"/>
<field name="col2" class="java.lang.Integer"/>
<field name="col3" class="java.lang.Integer"/>
<field name="col4" class="java.lang.Integer"/>
<field name="col5" class="java.lang.Integer"/>
<variable name="FAKE" class="java.lang.String">
<variableExpression><![CDATA["FAKE"]]></variableExpression>
</variable>
<detail>
<band height="20">
<textField evaluationTime="Auto">
<reportElement style="Fake" x="0" y="0" width="100" height="20"/>
<textFieldExpression><![CDATA[some.package.Storage.add($P{STORAGE}, $P{KEY}, $F{col1})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="ColoredText" x="0" y="0" width="100" height="20"/>
<textFieldExpression><![CDATA[$P{STORAGE}.get($P{KEY})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="Fake" x="100" y="0" width="100" height="20"/>
<textFieldExpression><![CDATA[some.package.Storage.add($P{STORAGE}, $P{KEY}, $F{col2})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="ColoredText" x="100" y="0" width="100" height="20"/>
<textFieldExpression><![CDATA[$P{STORAGE}.get($P{KEY})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="Fake" x="200" y="0" width="100" height="20"/>
<textFieldExpression><![CDATA[some.package.Storage.add($P{STORAGE}, $P{KEY}, $F{col3})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="ColoredText" x="200" y="0" width="100" height="20"/>
<textFieldExpression><![CDATA[$P{STORAGE}.get($P{KEY})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="Fake" x="300" y="0" width="100" height="20"/>
<textFieldExpression><![CDATA[some.package.Storage.add($P{STORAGE}, $P{KEY}, $F{col4})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="ColoredText" x="300" y="0" width="100" height="20"/>
<textFieldExpression><![CDATA[$P{STORAGE}.get($P{KEY})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="Fake" x="400" y="0" width="140" height="20"/>
<textFieldExpression><![CDATA[some.package.Storage.add($P{STORAGE}, $P{KEY}, $F{col5})]]></textFieldExpression>
</textField>
<textField evaluationTime="Auto">
<reportElement style="ColoredText" x="400" y="0" width="140" height="20"/>
<textFieldExpression><![CDATA[$P{STORAGE}.get($P{KEY})]]></textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
The green color is used for positive numbers and blue - for negative. The red color is using to indicate algorithm's problems.
Output result
The generated pdf with help of JRPdfExporter: