Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
374 views
in Technique[技术] by (71.8m points)

jasper reports - How to get current element in JasperReports when using conditionalExpression with styles?

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*?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

  1. We need parameter of Map type for storing the value of field (it will be abstract field - "coln")
  2. 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.
  3. 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

  1. The import for our utitlity class should be added for using it.

  2. 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

  3. 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.

  4. 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:

The generated pdf


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...