If you like to use this in a swing application your main problem (at least in jasper report version <6.1.1) is that you have no direct method to add a JRHyperLinkListener
From source code of JRViewer
:
//FIXME add a method to do addHyperlinkListener without subclassing
protected JRViewerPanel createViewerPanel(){return new JRViewerPanel(viewerContext);}
I will show you a way how you can subclass this class, implement the JRHyperlinkListener
and open a new frame with a report name received from link.
Java code
Creating a class that extends the net.sf.jasperreports.swing.JRViewer
and implements the net.sf.jasperreports.view.JRHyperlinkListener
, I'm adding imports since library have old classes with same name,
import java.awt.BorderLayout;
import java.util.HashMap;
import javax.swing.JFrame;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRPrintHyperlink;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.swing.JRViewer;
import net.sf.jasperreports.swing.JRViewerPanel;
import net.sf.jasperreports.view.JRHyperlinkListener;
public class HyperLinkTest extends JRViewer implements JRHyperlinkListener {
private static final long serialVersionUID = -6429615130889276357L;
public HyperLinkTest(JasperPrint jrPrint){
super(jrPrint);
}
/**
* Since JRViewerPanel is protected our only way to add listener is
* to Override
*/
@Override
protected JRViewerPanel createViewerPanel()
{
JRViewerPanel panel = new JRViewerPanel(viewerContext);
panel.addHyperlinkListener(this);
return panel;
}
/**
* The listener gets the hyperlink reference and open relative report
*/
@Override
public void gotoHyperlink(JRPrintHyperlink arg) throws JRException {
JasperReport report = JasperCompileManager.compileReport("jasper/" + arg.getHyperlinkReference() + ".jrxml");
JasperPrint jasperPrint = JasperFillManager.fillReport(report, new HashMap<String, Object>());
HyperLinkTest nextReport = new HyperLinkTest(jasperPrint);
openReport("Navigated to", JFrame.DISPOSE_ON_CLOSE, nextReport);
}
/**
* static method that creates a frame and adds the JRViewer to it and
* open a new frame with the viewer
*/
public static void openReport(String title, int defaultCloseOperation, JRViewer hyperLinkReport){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(defaultCloseOperation);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(hyperLinkReport,BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
/**
* Main method to test
*/
public static void main(String[] args) throws JRException {
JasperReport report = JasperCompileManager.compileReport("jasper/hyperlink1.jrxml");
JasperPrint jasperPrint = JasperFillManager.fillReport(report, new HashMap<String, Object>());
HyperLinkTest test = new HyperLinkTest(jasperPrint);
openReport("Test hyperlink", JFrame.EXIT_ON_CLOSE, test);
}
}
Jrxml (reports)
As can be seen in code I'm using hyperlinkType="ReportExecution"
and in passing name of next report in hyperlinkReferenceExpression
.
Report 1 (hyperlink1.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="hyperlink1" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="601103bc-66ab-45a5-8422-ccb6f3e02ec2">
<queryString>
<![CDATA[]]>
</queryString>
<title>
<band height="50">
<textField hyperlinkType="ReportExecution">
<reportElement x="0" y="0" width="100" height="20" uuid="8dc8f664-60b3-4b10-8a55-23120bea1f85"/>
<textElement>
<font size="14" isBold="true"/>
</textElement>
<textFieldExpression><![CDATA["Hello"]]></textFieldExpression>
<hyperlinkReferenceExpression><![CDATA["hyperlink2"]]></hyperlinkReferenceExpression>
</textField>
</band>
</title>
</jasperReport>
Report 2 (hyperlink2.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="hyperlink1" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="601103bc-66ab-45a5-8422-ccb6f3e02ec2">
<queryString>
<![CDATA[]]>
</queryString>
<title>
<band height="50">
<textField hyperlinkType="ReportExecution">
<reportElement x="113" y="0" width="100" height="20" uuid="8dc8f664-60b3-4b10-8a55-23120bea1f85"/>
<textElement>
<font size="14" isBold="true"/>
</textElement>
<textFieldExpression><![CDATA["World"]]></textFieldExpression>
<anchorNameExpression><![CDATA["World"]]></anchorNameExpression>
<hyperlinkReferenceExpression><![CDATA["hyperlink1"]]></hyperlinkReferenceExpression>
</textField>
</band>
</title>
</jasperReport>
Result
First window will open with "Hello", if you click "Hello", second window will open with "World"

Notes: If I did this application probably I would pre-compile all .jrxml
to .jasper
, hence avoid compiling during run-time and probably I would have used multiple classes (1 for frame, 1 for viewer) avoiding static methods, however I have simplified to better fit SO format, concentrating on showing how a JRHyperLinkListener
can be implemented in a Swing application.
How to pass report parameters and other data
Can you please tell me how to pass connection Object and other parameters from first report to second from this comment
To pass objects (fields, parameters, variables or any other expression) to the JRHyperlinkListener
you should hyperlinkParameter
in jrxml.
Example (see the hyperlinkParameter
and it's hyperlinkParameterExpression
)
<?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="hyperlink1" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="601103bc-66ab-45a5-8422-ccb6f3e02ec2">
<parameter name="reportDate" class="java.util.Date" isForPrompting="false">
<defaultValueExpression><![CDATA[new java.util.Date()]]></defaultValueExpression>
</parameter>
....
<textField hyperlinkType="ReportExecution">
<reportElement x="0" y="0" width="100" height="20" uuid="8dc8f664-60b3-4b10-8a55-23120bea1f85"/>
<textElement>
<font size="14" isBold="true"/>
</textElement>
<textFieldExpression><![CDATA["Hello"]]></textFieldExpression>
<hyperlinkReferenceExpression><![CDATA["hyperlink2"]]></hyperlinkReferenceExpression>
<hyperlinkParameter name="reportTime">
<hyperlinkParameterExpression><![CDATA[$P{reportDate}]]></hyperlinkParameterExpression>
</hyperlinkParameter>
</textField>
....
</jasperReport>
This parameter can now be accessed by the JRHyperlinkListener
, in example I pass it to parameter map for next report, naturally the jphlp.getValue()
will continue to be instanceof java.util.Date
@Override
public void gotoHyperlink(JRPrintHyperlink arg) throws JRException {
Map<String, Object> nextReportParams = new HashMap<>();
List<JRPrintHyperlinkParameter> params = arg.getHyperlinkParameters().getParameters();
for (JRPrintHyperlinkParameter jphlp : params) {
if ("reportTime".equals(jphlp.getName())){
nextReportParams.put("previousReportTime",jphlp.getValue());
}
}
JasperReport report = JasperCompileManager.compileReport("jasper/" + arg.getHyperlinkReference() + ".jrxml");
JasperPrint jasperPrint = JasperFillManager.fillReport(report, nextReportParams);
HyperLinkTest nextReport = new HyperLinkTest(jasperPrint);
openReport("Navigated to", JFrame.DISPOSE_ON_CLOSE, nextReport);
}
Notes: Watch out passing main report datasource (this will be at the
end, you cannot re-use it, if you do not rewind it first) and
connection (this may be closed), it's better to pass a new connection to next report.