将条件表达式与样式一起使用时如何获取 JasperReports 中的当前元素?

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

我想在单元格的数值小于零时将 textValue 中的文本设置为红色。目前我的配置是这样的:

<style name="RedText">
    <conditionalStyle>
        <conditionExpression><![CDATA[$F{col1}.compareTo(BigDecimal.ZERO) == -1]]></conditionExpression>
        <style forecolor="#FF0000"/>
    </conditionalStyle>
</style>

我有更多的单元格(col2、col3、col4 ...)需要应用这种红色文本样式。是否有可能使它对当前值等具有通用性。col*?

不使用Java代码的standard/classical方法

不使用Java代码是不可能的。在您的情况下,您需要为每个字段创建新样式并将此具体样式应用于 textField 元素,其中 conditionExpression 包含具体值 字段.

通常情况下textField的表达式可能很复杂,conditionExpression也是如此。样式不知道它属于哪个控件。我们不能使用抽象字段的值(parameter/variable),引擎需要具体的名称来计算表达式。

使用 Java API

是否可以使用 JasperReports Java API 解决应用样式的任务。例如:

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);

使用后门或"yes we like to hack"

看看Java中美丽的class是地图,它在[=65中是无价的=]JasperReports。可以帮助我们破解这个任务。

  1. 我们需要 Map 类型的参数来存储字段的值(它将是抽象字段 - "coln"
  2. 我们需要在解析 textField 的表达式时启用应用样式。 属性 net.sf.jasperreports.style.evaluation.time.enabled 将有助于启用此功能。
  3. 我们需要一些 Java 方法来将值放入 Map(作为 "coln") 其中 returns 我们刚刚输入的值。 Map.put(K key, V value) 不适用于此目的。我用 Map.put 方法的包装器编写了小型实用程序 class。

数据源

使用简单的 csv 数据源就足够了。我喜欢这种用于测试和调试的数据源。

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

下例中此数据源的数据适配器名称为numbers.csv。文件的第一行被跳过 - 它包含列的名称。

Java代码

这是一个非常简单的实用程序class

public class Storage {

    public static Integer add(Map<String, Integer> map, String key, Integer value) {
        map.put(key, value);
        return value;
    }
}

报告模板

  1. 我们的实用程序 class 的导入应该添加以便使用它。

  2. 为了正确解析条件式的表达式,我们需要在表达式中使用一些参数或变量(你可以查看[=65=的源代码]JasperReports)。我将添加一些假变量用于 conditionExpression

  3. 我们需要把"coln"的值放到Map中,然后使用这个值条件样式。在这种情况下,我们不需要知道我们在 条件样式 中检查的字段名称。该参数将用于存储Map.

  4. 我们需要分两次放置和绘制"coln"的值。我们可以使用伪造的不可见 textField 将字段的值放入 Map 和另一个 textField 来显示值应用条件样式。 textField 的位置和大小相同 - 一个在另一个之上。

我们的条件是这样的:

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

conditionExpression 中没有 field 并且有效:)

jrxml 文件:

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

绿色用于正数,蓝色用于负数。红色用于表示算法的问题。

输出结果

借助JRPdfExporter生成的pdf: