Reputation: 1237
In my one of Java swing desktop based applications, I am using a JTable
and I added the sorting functionality for a column. I need to sort it according to the number values added by the user and then get the jasper report output.
Currently after the sorting and print the report, the report is not showing the sorted order. But the order when the values taken from the DB. How can I print the report which the user's table sorting order?
This is my jasper report generating code
try {
DefaultTableModel de = (DefaultTableModel)Dashboard.catalogTbl.getModel();
JRTableModelDataSource jr = new JRTableModelDataSource(de);
String reportName = reportPath + "reports/AuctionSale/Catalogue/catalouge_frm_tbl.jrxml";
String compiledName = reportPath + "reports/AuctionSale/Catalogue/catalouge_frm_tbl.jasper";
Map<String, Object> params = new HashMap<String, Object>();
params.put("Lot_No", "Lot No");
params.put("Mark", "Mark");
params.put("Invoice", "Invoice");
params.put("Grade", "Grade");
params.put("Weight", "Weight");
params.put("Price", "Price");
params.put("Buyer", "Buyer");
JasperCompileManager.compileReportToFile(reportName, compiledName);
JasperPrint jasperPrint = JasperFillManager.fillReport(compiledName, params, jr);
JasperViewer.viewReport(jasperPrint, false);
} catch (Exception e) {
e.printStackTrace();
}
Upvotes: 2
Views: 3362
Reputation: 1
In this code, what I do is that after applying the filters in the jTable1, place the rows obtained in the auxiliary model.
Then I assigned the auxiliary model to the auxiliary table. And that table is the one I'll send to JasperReports.
//** jTable1 is the table in the jFrame where the data is loaded and I apply
//the RowFilter or RowSorter filters
DefaultTableModel dataModel_tableFiltered = null; //auxiliary model
JTable tableAuxiliary = null; //table where we will put the auxiliary model
public constructor {
dataModel_tableFiltered = new DefaultTableModel ();
// Set the number and name of the columns in the auxiliary model
for (int i = 0; i <jTable1.getColumnCount(); i ++) {
dataModel_tableFiltered.addColumn(jTable1.getColumnName (i));
}
tableAuxiliary = new JTable ();
}
private void btn_PrintActionPerformed (java.awt.event.ActionEvent evt) {
fillModel_filtered ();
try {
Map params = new HashMap ();
params.put ("nameCustomer", "**");
JRDataSource dataSource = new JRTableModelDataSource (tableAuxiliary.getModel ());
JasperPrint print = JasperFillManager.fillReport (reportPath, params, dataSource);
JasperViewer.viewReport (print, false); // true == Exit on Close
} catch (JRException ex) {
ex.printStackTrace ();
}
}
// Put resulting rows in the model after applying filters in jTable1
public void fillModel_filtered () {
dataModel_tableFiltered.setRowCount (0); // Empty rows of the model
for (int i = 0; i <jTable1.getRowCount (); i ++) {
Object row [] = new Object [jTable1.getColumnCount ()];
for (int j = 0; j <jTable1.getColumnCount (); j ++) {
row [j] = jTable1.getValueAt (i, j);
}
dataModel_tableFiltered.addRow (row);
}
tableAuxiliary.setModel(dataModel_tableFiltered); // Very Important
}
Upvotes: 0
Reputation: 51525
@Robin answer is basically correct, just translating to jasper speak :-)
The "decorator" is a custom implementation of JRDataSource or (here) JRRewindableDataSource. Make it data-only and base on the table's RowSorter, something like (beware: just compiled, not tested!)
public class JRTableSorterDataSource implements JRRewindableDataSource {
private RowSorter<? extends TableModel> sorter;
private int currentRow = -1;
private HashMap<String, Integer> columnNames = new HashMap<String, Integer>();
public JRTableSorterDataSource(RowSorter<? extends TableModel> sorter) {
if (sorter == null) return; // do nothing, no sorter
this.sorter = sorter;
TableModel tableModel = sorter.getModel();
if (tableModel != null) {
for (int i = 0; i < tableModel.getColumnCount(); i++) {
this.columnNames.put(tableModel.getColumnName(i),
Integer.valueOf(i));
}
}
}
@Override
public Object getFieldValue(JRField field) throws JRException {
String fieldName = field.getName();
Integer columnIndex = this.columnNames.get(fieldName);
return sorter.getModel().getValueAt(sorter.convertRowIndexToModel(currentRow), columnIndex.intValue());
}
@Override
public boolean next() throws JRException {
if (sorter == null || sorter.getModel() == null)
return false;
this.currentRow++;
return (this.currentRow < sorter.getViewRowCount());
}
@Override
public void moveFirst() throws JRException {
this.currentRow = -1;
}
protected int getColumnIndex(JRField field) throws JRException {
String fieldName = field.getName();
Integer columnIndex = this.columnNames.get(fieldName);
if (columnIndex != null) {
return columnIndex;
} else if (fieldName.startsWith("COLUMN_")) {
return Integer.parseInt(fieldName.substring(7));
}
throw new JRException("Unknown column name : " + fieldName);
}
}
Then use it when setting up your report:
JRDataSource jr = new JRTableSorterDataSource(Dashboard.catalogTbl.getRowSorter());
/// ... same as your example
Edit
just a very quick runnable snippet (too lazy to do a full report, forgot how those files work ;-) - so here we create a table (with a standard SwingX model), create a dataSource on its RowSorter and loop over the values of the first column, no problem:
JTable table = new JXTable(new AncientSwingTeam());
JRDataSource source = new JRTableSorterDataSource(table.getRowSorter());
table.getRowSorter().toggleSortOrder(0);
JRField field = createField("First Name");
String firstNames = "First Name: ";
while (source.next()) {
firstNames += "\n " + source.getFieldValue(field);
}
LOG.info(firstNames);
Upvotes: 2
Reputation: 36611
I guess the report is generated based on the TableModel
, while typical sorting only affect the JTable
itself, not the model.
What you could do is decorate the table model which you pass to your report generator so that it takes over the ordering of your JTable
. Something in the style of
public class TableModelDecorator implements TableModel{
private TableModel delegate;
private JTable table;
@Override
public Object getValueAt( int rowIndex, int columnIndex ) {
return delegate.getValueAt( table.convertRowIndexToView( rowIndex ), table.convertColumnIndexToView( columnIndex ) );
}
}
but then for all relevant methods.
Upvotes: 2