How to format merged cell as currency in excel using java? - java

i have merged the cell using apache poi and java but i wanted those merged cell to formats as currency.
after merged the cell in the code i added the cellstyle.setDataformat((short)8); but when i open the excel it is not showing format as currency . it shows as general.
Could you please share a working code to merge a cell with data format as currency ?
thank you in advance.

It is not really clear from your question what exactly is the problem here. There is no special requirement for cells having number format whether in merged regions or not.
What one needs to know is that merged regions only show the top left cell in whole merged region. That means the cell value as well as the cell style of the top left cell in whole merged region gets used.
The following is a minimal, reproducible example to show this.
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
class CreateExcelMergedCellsCurrencyFormat {
public static void main(String[] args) throws Exception {
Object[][] data = new Object[][] {
new String[] {"Name", "va", "lu", "es"},
new Object[] {"a", 123.456d, null, null},
new Object[] {"b", 0, null, null},
new Object[] {"c", -123.456d, null, null},
new Object[] {"d", 1000000L, null, null},
new Object[] {"e", -1000000, null, null}
};
int firstRow = 3;
int firstCol = 2;
int mergeFromCol = firstCol + 1;
int mergeToCol = firstCol + 3;
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("./Excel.xlsx") ) {
CellStyle currencyStyle = workbook.createCellStyle();
currencyStyle.setDataFormat(workbook.createDataFormat().getFormat(BuiltinFormats.getBuiltinFormat(8)));
Sheet sheet = workbook.createSheet();
int r = firstRow;
for (Object[] rowData : data) {
Row row = sheet.createRow(r);
int c = firstCol;
for (Object cellValue : rowData) {
Cell cell = row.createCell(c);
if (cellValue instanceof String) {
cell.setCellValue((String)cellValue);
} else if (cellValue instanceof Number) {
cell.setCellValue(((Number)cellValue).doubleValue());
cell.setCellStyle(currencyStyle);
}
c++;
}
if (r > firstRow) sheet.addMergedRegion(new CellRangeAddress(row.getRowNum(), row.getRowNum(), mergeFromCol, mergeToCol));
r++;
}
workbook.write(fileout);
}
}
}

Related

Apply Conditional Formatting to Entire Row Specific Only to That Row

I am trying to create Conditional Formatting that has multiple different rules based off different values, that will only apply to the row that the value matches in. Here is the code I have so far for some context.
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet("new sheet");
// Create a row and put some cells in it. Rows are 0 based.
XSSFRow row1 = sheet.createRow(0);
// Create a cell
row1.createCell(0).setCellValue("Lot Type");
row1.createCell(1).setCellValue("Lot Size");
row1.createCell(2).setCellValue("Square Footage");
row1.createCell(3).setCellValue("Heating/Cooling");
row1.createCell(4).setCellValue("Extras");
XSSFRow row2 = sheet.createRow(1);
row2.createCell(0).setCellValue("Residential");
row2.createCell(1).setCellValue("8000");
row2.createCell(2).setCellValue("1200");
row2.createCell(3).setCellValue("Yes");
row2.createCell(4).setCellValue("None");
XSSFRow row3 = sheet.createRow(1);
row3.createCell(0).setCellValue("Industrial");
row3.createCell(1).setCellValue("12000");
row3.createCell(2).setCellValue("8000");
row3.createCell(3).setCellValue("");
row3.createCell(4).setCellValue("");
// Set conditional rules
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule("$A2 = " + "\"" + "Residential" + "\"");
PatternFormatting fill = rule.createPatternFormatting();
fill.setFillBackgroundColor(IndexedColors.YELLOW.index);
fill.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
CellRangeAddress[] regions = new CellRangeAddress[]{CellRangeAddress.valueOf("C2"), CellRangeAddress.valueOf("E2")};
ConditionalFormattingRule[] cfRules = new ConditionalFormattingRule[]{rule};
sheetCF.addConditionalFormatting(regions,cfRules);
// Write the output to a file
return wb;
So this works, but only if Row 2 A column has the value "Residential" entered. What I want to happen, is "Lot Type" will have a drop down list with different options ('Residential', 'Industrial', 'Agriculture', etc) and each "Lot Type" would have different "required" fields, and I don't know what the user will select per row for each row.
The possible options, both in terms of rows and possible drop downs choices, is large. At the moment, 10000 rows are generated each with 40+ drop down options. That isn't specifically necessary information, but what it does mean is that simply looping through i < 10000 and just incrementing the row index; "A#", "C#", etc, and then with each index looping through all my drop down option rules, is not a viable solution.
If that is the only option, so be it, but I was hoping there was a way I could do something with Excel equations or conditional formatting where I can connect the different "Lot Types" to their required columns, with the numbered index of the row dynamically used within the equation itself. Which means I would be able to just set the conditional formatting once on the possible rows, and not have to run through some massive double loop.
Something like the following, which I have tried and it did not work:
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule("$A$ = " + "\"" + "Residential" + "\"");
PatternFormatting fill = rule.createPatternFormatting();
fill.setFillBackgroundColor(IndexedColors.YELLOW.index);
fill.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
CellRangeAddress[] regions = new CellRangeAddress[]{CellRangeAddress.valueOf("C$"), CellRangeAddress.valueOf("E$")};
How I would envision this to work in words would be that what ever row index has the value "Residential" inputted into the A cell, it would cause that respective row's, and only that row's, C and E cells to be highlighted
Thanks in advance for any help!
Excel is not really good at pointing the user to the required cells to fill in. As long as always the same columns needs to be filled, either data validation or conditional formatting offer themselves. But if the mandatory columns are conditional by them self, then this leads very fast to thousands of different data validation or conditional formatting rules. And this is not practicable as you mentioned already.
But the question you asked was about a conditional formula rule which gets adjusted to different rows automatically. And this is possible.
Conditional formula rules, as well as default formulas, respect the $ mark in cell references to differentiate between fixed and variable cell references. So if a formula rule =($A2="Residential") gets applied to the range A2:E1000, then the row reference to row 2 gets adjusted in other rows because it is variable and not fixed by $. So it checks =($A2="Residential") in row 2, =($A3="Residential") in row 3, =($A4="Residential") in row 4 and so on.
But of course the conditional formatting gets applied to all the columns in the given range A2:E1000. So if the rule matches in a row, all columns A:E get formatted. And this is the problem. If only the required columns shall be highlighted, then there would must be multiple different cell ranges where the conditional formatting gets applied. And this leads to your mentioned thousands of possibilities in your case.
One solution, I can think of, would be having different formula rules per identifier (Lot Type in your case) which may have different rules for required columns per identifier. And as long one of those rules is violated, then the whole row gets highlighted. This would be solvable having as much conditional formatting rules as different identifiers are, all applied to the whole data range.
Complete example:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import java.io.FileOutputStream;
public class ConditionalFormattingRulesAndRanges {
public static void main(String[] args) throws Exception {
Object[][] data = new Object[][] {
new Object[] {"Lot Type", "Lot Size", "Square Footage", "Heating/Cooling", "Extras"},
new Object[] {"Residential", 8000, 1200, "Yes", "None"},
new Object[] {"Industrial", 12000, 8000, "", ""},
new Object[] {"Agriculture", 4000, 900, "No", "Much"},
new Object[] {"Industrial", 10000, "", "Yes", ""},
new Object[] {"Residential", 8500, 1000, "", "None"},
new Object[] {"Agriculture", 9000, "", "", ""}
};
int dataRowCount = data.length;
int columnCount = data[0].length;
String[] identifiers = new String[] {"Residential", "Industrial", "Agriculture"};
String[] requiredColumnsRules = new String[] {"OR($C2=\"\",$D2=\"\",$E2=\"\")", "OR($C2=\"\",$D2=\"\")", "$C2=\"\""};
int identifiersCount = identifiers.length;
Workbook workbook = new XSSFWorkbook(); String filePath ="./ConditionalFormattingRulesAndRanges.xlsx";
int lastRow = workbook.getSpreadsheetVersion().getLastRowIndex();
Sheet sheet = workbook.createSheet();
int r = 0;
for (Object[] rowData : data) {
Row row = sheet.createRow(r);
int c = 0;
for (Object cellValue : rowData) {
Cell cell = row.createCell(c);
if (cellValue instanceof Number) {
cell.setCellValue(((Number)cellValue).doubleValue());
} else {
cell.setCellValue(String.valueOf(cellValue));
}
c++;
}
r++;
}
for (int i = 0; i < columnCount; i++) {
sheet.autoSizeColumn(i);
}
sheet.createFreezePane(1,1,1,1);
DataValidationHelper dvHelper = sheet.getDataValidationHelper();
DataValidationConstraint dvConstraint = dvHelper.createExplicitListConstraint(identifiers) ;
CellRangeAddressList addressList = new CellRangeAddressList(1, lastRow, 0, 0);
DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
validation.createPromptBox("Hint", "If the line is highlighted in yellow, mandatory fields are not filled out.");
if (workbook instanceof XSSFWorkbook) validation.setShowPromptBox(true);
sheet.addValidationData(validation);
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
ConditionalFormattingRule[] cfRules = new ConditionalFormattingRule[identifiersCount];
for (int i = 0; i < identifiersCount; i++) {
String identifier = identifiers[i];
String requiredColumnsRule = requiredColumnsRules[i];
String formulaRule = "AND($A2 = " + "\"" + identifier + "\"," + requiredColumnsRule + ")"; // rule will be applied from row 2 on; Row reference is not fixed, so it will be adjusted
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule(formulaRule);
PatternFormatting patternFmt = rule.createPatternFormatting();
patternFmt.setFillBackgroundColor(IndexedColors.YELLOW.index);
cfRules[i] = rule;
}
CellRangeAddress[] dataRange = new CellRangeAddress[]{CellRangeAddress.valueOf("A2:E" + lastRow)}; // rules applied to the whole possible data range
sheetCF.addConditionalFormatting(dataRange, cfRules);
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}
Another solution would be having one conditional formatting rule per mandatory column. That rule would must define per formula for which identifiers this column is a mandatory column. This needs one complete conditional formatting for each mandatory column.
Complete example for this:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import java.io.FileOutputStream;
public class ConditionalFormattingRulesAndRanges2 {
public static void main(String[] args) throws Exception {
Object[][] data = new Object[][] {
new Object[] {"Lot Type", "Lot Size", "Square Footage", "Heating/Cooling", "Extras"},
new Object[] {"Residential", 8000, 1200, "Yes", "None"},
new Object[] {"Industrial", 12000, 8000, "", ""},
new Object[] {"Agriculture", 4000, 900, "No", "Much"},
new Object[] {"Industrial", 10000, "", "Yes", ""},
new Object[] {"Residential", 8500, 1000, "", "None"},
new Object[] {"Agriculture", 9000, "", "", ""}
};
int dataRowCount = data.length;
int columnCount = data[0].length;
String[] identifiers = new String[] {"Residential", "Industrial", "Agriculture"};
String[] rules = new String[] { // rule will be applied from row 2 on; Row reference is not fixed, so it will be adjusted
"AND($C2=\"\",OR($A2=\"Residential\",$A2=\"Industrial\",$A2=\"Agriculture\"))", // column C needs to be filled for all identifiers
"AND($D2=\"\",OR($A2=\"Residential\",$A2=\"Industrial\"))", // column D needs to be filled for Residential and Industrial only
"AND($E2=\"\",OR($A2=\"Residential\"))" // column E needs to be filled for Residential only
};
int rulesCount = rules.length;
Workbook workbook = new XSSFWorkbook(); String filePath ="./ConditionalFormattingRulesAndRanges.xlsx";
int lastRow = workbook.getSpreadsheetVersion().getLastRowIndex();
CellRangeAddress[][] rulesAppliedTo = new CellRangeAddress[][] {
new CellRangeAddress[]{CellRangeAddress.valueOf("C2:C" + lastRow)},
new CellRangeAddress[]{CellRangeAddress.valueOf("D2:D" + lastRow)},
new CellRangeAddress[]{CellRangeAddress.valueOf("E2:E" + lastRow)}
};
Sheet sheet = workbook.createSheet();
int r = 0;
for (Object[] rowData : data) {
Row row = sheet.createRow(r);
int c = 0;
for (Object cellValue : rowData) {
Cell cell = row.createCell(c);
if (cellValue instanceof Number) {
cell.setCellValue(((Number)cellValue).doubleValue());
} else {
cell.setCellValue(String.valueOf(cellValue));
}
c++;
}
r++;
}
for (int i = 0; i < columnCount; i++) {
sheet.autoSizeColumn(i);
}
sheet.createFreezePane(1,1,1,1);
DataValidationHelper dvHelper = sheet.getDataValidationHelper();
DataValidationConstraint dvConstraint = dvHelper.createExplicitListConstraint(identifiers) ;
CellRangeAddressList addressList = new CellRangeAddressList(1, lastRow, 0, 0);
DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
validation.createPromptBox("Hint", "If a cell is highlighted in yellow, then this is a mandatory.");
if (workbook instanceof XSSFWorkbook) validation.setShowPromptBox(true);
sheet.addValidationData(validation);
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
for (int i = 0; i < rulesCount; i++) {
String formulaRule = rules[i];
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule(formulaRule);
PatternFormatting patternFmt = rule.createPatternFormatting();
patternFmt.setFillBackgroundColor(IndexedColors.YELLOW.index);
ConditionalFormattingRule[] cfRules = new ConditionalFormattingRule[]{rule};
CellRangeAddress[] appliedTo = rulesAppliedTo[i];
sheetCF.addConditionalFormatting(appliedTo, cfRules);
}
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}

Apache POI: How to set THIS_YEAR filter in row label date of a pivot

I am trying to create a pivot in excel using apache poi.
My requirement is to apply the Date Filter (THIS YEAR) i.e to show only current year dates in the date row label in the pivot.
Problem: Below the reproducible code that generates output excel file with "THIS_YEAR" filter applied to the date column but for some reason, it's not showing any data.
Below is the code to generate the output.
import java.io.FileOutputStream;
import org.apache.poi.ss.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import java.util.GregorianCalendar;
class CreatePivotTableFilter {
public static void main(String[] args) throws Exception {
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {
DataFormat format = workbook.createDataFormat();
CellStyle dateStyle = workbook.createCellStyle();
dateStyle.setDataFormat(format.getFormat("M\\/d\\/yy"));
Sheet sheet = workbook.createSheet();
String[] headers = new String[]{"Column1", "Column2", "Date", "Count"};
Row row = sheet.createRow(0);
Cell cell;
for (int c = 0; c < headers.length; c++) {
cell = row.createCell(c); cell.setCellValue(headers[c]);
}
Object[][] data = new Object[][]{
new Object[]{"A", "B1", new GregorianCalendar(2020, 0, 2), 2d},
new Object[]{"A", "B2", new GregorianCalendar(2020, 0, 1), 4d},
new Object[]{"B", "B1", new GregorianCalendar(2019, 0, 2), 1d},
new Object[]{"B", "B2", new GregorianCalendar(2019, 0, 2), 7d},
new Object[]{"A", "C1", new GregorianCalendar(2019, 0, 1), 5d},
new Object[]{"A", "C2", new GregorianCalendar(2019, 0, 1), 5d},
new Object[]{"B", "C1", new GregorianCalendar(2019, 0, 2), 2d},
new Object[]{"B", "C2", new GregorianCalendar(2019, 0, 2), 8d}
};
for (int r = 0; r < data.length; r++) {
row = sheet.createRow(r+1);
Object[] rowData = data[r];
for (int c = 0; c < rowData.length; c++) {
cell = row.createCell(c);
if (rowData[c] instanceof String) {
cell.setCellValue((String)rowData[c]);
} else if (rowData[c] instanceof GregorianCalendar) {
cell.setCellValue((GregorianCalendar)rowData[c]);
cell.setCellStyle(dateStyle);
} else if (rowData[c] instanceof Double) {
cell.setCellValue((Double)rowData[c]);
}
}
}
XSSFPivotTable pivotTable = ((XSSFSheet)sheet).createPivotTable(
new AreaReference("A1:D9",
SpreadsheetVersion.EXCEL2007),
new CellReference("F4"));
pivotTable.addRowLabel(0);
pivotTable.addRowLabel(1);
pivotTable.addRowLabel(2);
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 3);
pivotTable.addColumnLabel(DataConsolidateFunction.AVERAGE, 3);
CTPivotFilters filters = CTPivotFilters.Factory.newInstance();
CTPivotFilter filter = filters.addNewFilter();
filter.setId(0);
filter.setFld(2);
filter.setType(STPivotFilterType.THIS_YEAR);
CTFilterColumn filterColumn = filter.addNewAutoFilter().addNewFilterColumn();
filterColumn.setColId(0);
CTFilters ctFilters = filterColumn.addNewFilters();
ctFilter.addNewFilter().setVal("This Year Filter");
//set filters to pivot table definition
pivotTable.getCTPivotTableDefinition().setFilters(filters);
workbook.write(fileout);
}
}
}
Output generated by code
Expected Output
Best way dealing with the low level ooxml-schemas classes is creating whatever one wants using Excel's GUI, then unzipping the resulting *.xlsx file and having a look at the XML what the GUI has created.
In that case in xl/pivotTables/pivotTable1.xml we find:
...
<filters>
<filter fld="2" type="thisYear" id="0">
<autoFilter>
<filterColumn colId="0">
<dynamicFilter type="thisYear"/>
</filterColumn>
</autoFilter>
</filter>
</filters>
...
So filterColumn does not contain <filters><filter ...> but contains dynamicFilter of type thisYear.
So your code would must be:
...
CTPivotFilters filters = CTPivotFilters.Factory.newInstance();
CTPivotFilter filter = filters.addNewFilter();
filter.setId(0);
filter.setFld(2);
filter.setType(STPivotFilterType.THIS_YEAR);
CTFilterColumn filterColumn = filter.addNewAutoFilter().addNewFilterColumn();
filterColumn.setColId(0);
CTDynamicFilter ctDynamicFilter = filterColumn.addNewDynamicFilter();
ctDynamicFilter.setType(STDynamicFilterType.THIS_YEAR);
//set filters to pivot table definition
pivotTable.getCTPivotTableDefinition().setFilters(filters);
...
Unfortunately there is not any API documentation of ooxml-schemas public available. So if we need it, we need to download ooxml-schemas sources from maven. Then we can create a API documentation using javadoc. There then we can find fields and methods of CTFilterColumn for example.

Issue with export CrossTab data into excel sheet using Java Apache POI 3.15 version

I am collecting data from my company portal and trying to export it into an excel sheet. I successfully completed for non-crosstab report data. But the issue is coming when the data has crosstab.
Data:
I have saved in data in ArrayList best on my best understanding.
1.
rowHeader:[Quarter, Subcategory]
2.
rowElement:[2016 Q1, 2016 Q2, 2016 Q3, 2016 Q4, Audio Equipment, Cameras, Computers, Electronics - Miscellaneous, TV's, Video Equipment]
3.
columnHeader:[Year, 2016]
4.
columnHeaders[Quarter, Subcategory, Year, 2016]
5.
metricsColumn:[Metrics, Profit, Profit Forecast, Profit Margin, Revenue, Revenue Forecast]
6.
listData:[[$9,579, $8,823, 19.42%, $49,320, $ 39,456], [$11,449, $9,619, 20.07%, $57,040, $ 53,047], [$4,901, $3,784, 20.02%, $24,480, $ 21,298], [$12,444, $9,525, 19.89%, $62,576, $ 53,815], [$8,820, $8,059, 20.19%, $43,675, $ 35,814], [$16,375, $12,986, 20.44%, $80,130, $ 70,514], [$8,526, $6,929, 15.78%, $54,020, $ 49,698], [$11,602, $9,578, 17.31%, $67,032, $ 63,680], [$4,675, $4,380, 16.83%, $27,780, $ 25,752], [$11,699, $9,421, 16.60%, $70,469, $ 54,966], [$9,386, $7,179, 17.52%, $53,563, $ 49,974], [$10,150, $9,213, 16.96%, $59,864, $ 48,490], [$8,508, $6,772, 17.16%, $49,571, $ 47,092], [$16,429, $13,529, 18.52%, $88,712, $ 83,389], [$6,009, $5,391, 18.05%, $33,295, $ 29,200], [$11,792, $9,791, 17.21%, $68,534, $ 64,285], [$9,243, $7,952, 17.15%, $53,886, $ 49,953], [$14,282, $11,679, 18.03%, $79,193, $ 74,441], [$10,999, $8,538, 15.60%, $70,511, $ 65,575], [$14,475, $11,433, 16.32%, $88,718, $ 78,515], [$5,765, $5,029, 16.77%, $34,373, $ 31,847], [$11,335, $9,567, 15.28%, $74,168, $ 62,672], [$11,990, $11,230, 16.83%, $71,255, $ 64,414], [$13,864, $11,328, 16.87%, $82,203, $ 70,695]]
Till so far, I successfully, completed exporting Headers section.
I am struggling, now exporting data into an excel sheet because of the crosstab we need to do column merge and row merge for every Quarters and Years.
If someone can help me, to write any sample code/ pseudo code for it, it would be a very very helpful for me. I ave stuck with this issue from the last 4 days. I am not getting how to do this part as I never used any exclsheet API. here I am using APACHE POI -3.15 version.
Code till so far, which export Header section:
//Create a Row
Row headerRow = sheet.createRow(0);
//int totalcolumns = rowHeader.size() + columnHeader.size();
int mergeHeader = 0;
if(metricsColumn != null) {
mergeHeader = 1;
}
//Create Cells //[Quarter, Subcategory, Year, 2016]
int j = rowHeader.size();
int row = 0;
for (int i = 0; i < columnHeaders.size(); i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(columnHeaders.get(i));
if(j > 0) {
sheet.addMergedRegion(new CellRangeAddress(row, mergeHeader, i, i));
}
j--;
if (i == columnHeaders.size() - 1 && metricsColumn.size() > 0) {
sheet.addMergedRegion(new CellRangeAddress(0,0,i,i + metricsColumn.size() - 2));
}
cell.setCellStyle(headerCellStyle);
}
int k = 0;
int rowNum1 = 1;
int cellNum1 = 2;
Row row1 = sheet.createRow(rowNum1);
for (int i = rowHeader.size(); i < metricsColumn.size(); i++) {
while (k < metricsColumn.size()) {
Cell cell = row1.createCell(cellNum1++);
cell.setCellValue(metricsColumn.get(k));
cell.setCellStyle(headerCellStyle);
k++;
}
}
I would make the structures for headers and data a little bit different:
The headers for example:
String[][] headers = new String[][] {
new String[] {"Quarter", "Subcategory", "Year", "2016", null, null, null, null},
new String[] { null, null, "Metrics", "Profit", "Profit Forecast", "Profit Margin", "Revenue", "Revenue Forecast"}
};
Maybe List<List<String>> also would be possible.
The row headers:
String[] quarters = new String[]{"2016 Q1", "2016 Q2", "2016 Q3", "2016 Q4"};
String[] subcategories = new String[]{"Audio Equipment", "Cameras", "Computers", "Electronics - Miscellaneous", "TV's", "Video Equipment"};
Maybe List<String> also would be possible.
The values:
Double[][] values = new Double[][]{
new Double[]{9579d, 8823d, .1942, 49320d,39456d},
new Double[]{11449d, 9619d, .2007, 57040d, 53047d},
...
new Double[]{13864d, 11328d, .1687, 82203d, 70695d}
};
Maybe List<List<Double>> also would be possible.
Then I would also provide basic formatting instructions in structures. So it is later possible to set them using loops.
For example the basic table structure:
int[] columnWidths = new int[]{15*256, 15*256, 15*256, 13*256, 13*256, 13*256, 13*256, 13*256};
For example the headers horizontal alignment:
HorizontalAlignment[][] horizontalAlignments = new HorizontalAlignment[][]{
new HorizontalAlignment[]{HorizontalAlignment.LEFT, HorizontalAlignment.CENTER, HorizontalAlignment.LEFT, HorizontalAlignment.CENTER, null, null, null, null},
new HorizontalAlignment[]{null, null, HorizontalAlignment.RIGHT, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER}
};
And the merged regions for the headers:
int[][] headerMergedRegions = new int[][]{
new int[]{0, 0, 3, 7},
new int[]{0, 1, 0, 0},
new int[]{0, 1, 1, 1}
};
Then I would set the much used number formats in default column styles:
String[] columnCellStyles = new String[]{"default", "default", "default", "currency", "currency", "percent", "currency", "currency"};
...
// creating default cell style having default font
CellStyle defaultCellStyle = workbook.createCellStyle();
defaultCellStyle.setFont(defaultFont);
// we need currency style for numbers later
CellStyle currency = workbook.createCellStyle();
currency.cloneStyleFrom(defaultCellStyle);
currency.setDataFormat(format.getFormat("$#,##0"));
// we need percent style for numbers later
CellStyle percent = workbook.createCellStyle();
percent.cloneStyleFrom(defaultCellStyle);
percent.setDataFormat(format.getFormat("0.00%"));
...
// set default column styles
for (int c = 0; c < columnCellStyles.length; c++) {
String style = columnCellStyles[c];
if ("default".equals(style)) {
sheet.setDefaultColumnStyle(c, defaultCellStyle);
} else if ("currency".equals(style)) {
sheet.setDefaultColumnStyle(c, currency);
} else if ("percent".equals(style)) {
sheet.setDefaultColumnStyle(c, percent);
}
}
So when we set the values later, the cell styles can come from default column style. For this a method CellStyle getPreferredCellStyle(Cell cell) could be used.
For formatting I would rely on methods from CellUtil. So not all needed CellStyles needs to be created on workbook level but can be set to the cell into the loops.
For cell borders I would use PropertyTemplate. This makes setting borders much more easier.
Complete example:
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellUtil;
import org.apache.poi.ss.util.PropertyTemplate;
import java.util.Map;
import java.util.HashMap;
class CreateExcelSpecial {
static CellStyle getPreferredCellStyle(Cell cell) {
// a method to get the preferred cell style for a cell
// this is either the already applied cell style
// or if that not present, then the row style (default cell style for this row)
// or if that not present, then the column style (default cell style for this column)
CellStyle cellStyle = cell.getCellStyle();
// if no explicit cell style applied then cellStyle.getIndex() is 0 for XSSF
// or 15 (0xF = the index to the default ExtendedFormatRecord (0xF)) for HSSF
if ((cell instanceof XSSFCell && cellStyle.getIndex() == 0) || (cell instanceof HSSFCell && cellStyle.getIndex() == 15)) cellStyle = cell.getRow().getRowStyle();
if (cellStyle == null) cellStyle = cell.getSheet().getColumnStyle(cell.getColumnIndex());
if (cellStyle == null) cellStyle = cell.getCellStyle();
return cellStyle;
}
public static void main(String[] args) throws Exception {
// the data
// basic table structure
int[] columnWidths = new int[]{15*256, 15*256, 15*256, 13*256, 13*256, 13*256, 13*256, 13*256};
String[] columnCellStyles = new String[]{"default", "default", "default", "currency", "currency", "percent", "currency", "currency"};
// headers content and formatting
String[][] headers = new String[][] {
new String[] {"Quarter", "Subcategory", "Year", "2016", null, null, null, null},
new String[] { null, null, "Metrics", "Profit", "Profit Forecast", "Profit Margin", "Revenue", "Revenue Forecast"}
};
HorizontalAlignment[][] horizontalAlignments = new HorizontalAlignment[][]{
new HorizontalAlignment[]{HorizontalAlignment.LEFT, HorizontalAlignment.CENTER, HorizontalAlignment.LEFT, HorizontalAlignment.CENTER, null, null, null, null},
new HorizontalAlignment[]{null, null, HorizontalAlignment.RIGHT, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER}
};
VerticalAlignment[][] verticalAlignments = new VerticalAlignment[][]{
new VerticalAlignment[]{VerticalAlignment.TOP, VerticalAlignment.TOP, VerticalAlignment.CENTER, VerticalAlignment.CENTER, null, null, null, null},
new VerticalAlignment[]{null, null, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM}
};
Boolean[][] wrapTexts = new Boolean[][]{
new Boolean[]{false, false, false, false, null, null, null, null},
new Boolean[]{null, null, false, false, true, true, false, true}
};
int[][] headerMergedRegions = new int[][]{
new int[]{0, 0, 3, 7},
new int[]{0, 1, 0, 0},
new int[]{0, 1, 1, 1}
};
// row headers
String[] quarters = new String[]{"2016 Q1", "2016 Q2", "2016 Q3", "2016 Q4"};
String[] subcategories = new String[]{"Audio Equipment", "Cameras", "Computers", "Electronics - Miscellaneous", "TV's", "Video Equipment"};
// data
Double[][] values = new Double[][]{
new Double[]{9579d, 8823d, .1942, 49320d,39456d},
new Double[]{11449d, 9619d, .2007, 57040d, 53047d},
new Double[]{4901d, 3784d, .2002, 24480d, 21298d},
new Double[]{12444d, 9525d, .1989, 62576d, 53815d},
new Double[]{8820d, 8059d, .2019, 43675d, 35814d},
new Double[]{16375d, 12986d, .2044, 80130d, 70514d},
new Double[]{8526d, 6929d, .1578, 54020d, 49698d},
new Double[]{11602d, 9578d, .1731, 67032d, 63680d},
new Double[]{4675d, 4380d, .1683, 27780d, 25752d},
new Double[]{11699d, 9421d, .1660, 70469d, 54966d},
new Double[]{9386d, 7179d, .1752, 53563d, 49974d},
new Double[]{10150d, 9213d, .1696, 59864d, 48490d},
new Double[]{8508d, 6772d, .1716, 49571d, 47092d},
new Double[]{16429d, 13529d, .1852, 88712d, 83389d},
new Double[]{6009d, 5391d, .1805, 33295d, 29200d},
new Double[]{11792d, 9791d, .1721, 68534d, 64285d},
new Double[]{9243d, 7952d, .1715, 53886d, 49953d},
new Double[]{14282d, 11679d, .1803, 79193d, 74441d},
new Double[]{10999d, 8538d, .1560, 70511d, 65575d},
new Double[]{14475d, 11433d, .1632, 88718d, 78515d},
new Double[]{5765d, 5029d, .1677, 34373d, 31847d},
new Double[]{11335d, 9567d, .1528, 74168d, 62672d},
new Double[]{11990d, 11230d, .1683, 71255d, 64414d},
new Double[]{13864d, 11328d, .1687, 82203d, 70695d}
};
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("./Excel.xlsx") ) {
// we need PropertyTemplate later
PropertyTemplate propertyTemplate = new PropertyTemplate();
// we need properties map for cell styles later
Map<String, Object> properties;
// we need DataFormat later
DataFormat format = workbook.createDataFormat();
// creating default font
Font defaultFont = workbook.createFont();
defaultFont.setFontName("Calibri");
defaultFont.setFontHeightInPoints((short)12);
// we need font in bold and white for headings
Font defaultFontWhite = workbook.createFont();
defaultFontWhite.setFontName("Calibri");
defaultFontWhite.setFontHeightInPoints((short)12);
defaultFontWhite.setBold(true);
defaultFontWhite.setColor(IndexedColors.WHITE.getIndex());
// creating default cell style having default font
CellStyle defaultCellStyle = workbook.createCellStyle();
defaultCellStyle.setFont(defaultFont);
// we need currency style for numbers later
CellStyle currency = workbook.createCellStyle();
currency.cloneStyleFrom(defaultCellStyle);
currency.setDataFormat(format.getFormat("$#,##0"));
// we need percent style for numbers later
CellStyle percent = workbook.createCellStyle();
percent.cloneStyleFrom(defaultCellStyle);
percent.setDataFormat(format.getFormat("0.00%"));
Sheet sheet = workbook.createSheet();
// set column widths
for (int c = 0; c < columnWidths.length; c++) sheet.setColumnWidth(c, columnWidths[c]);
// set default column styles
for (int c = 0; c < columnCellStyles.length; c++) {
String style = columnCellStyles[c];
if ("default".equals(style)) {
sheet.setDefaultColumnStyle(c, defaultCellStyle);
} else if ("currency".equals(style)) {
sheet.setDefaultColumnStyle(c, currency);
} else if ("percent".equals(style)) {
sheet.setDefaultColumnStyle(c, percent);
}
}
int rowIdx = 0; // looping row index
int colIdx = 0; // looping column index
// input and format headers
int i = 0;
for (String[] headerRow : headers) {
Row row = sheet.createRow(rowIdx++);
colIdx = 0;
int j = 0;
for (String header : headerRow) {
Cell cell = row.createCell(colIdx++);
cell.setCellValue(header);
properties = new HashMap<String, Object>();
properties.put(CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
properties.put(CellUtil.FILL_FOREGROUND_COLOR, IndexedColors.BLUE.getIndex()); //do using only IndexedColors for fills
properties.put(CellUtil.FONT, defaultFontWhite.getIndexAsInt()); // white font
if (horizontalAlignments.length == headers.length) {
HorizontalAlignment[] hAligns = horizontalAlignments[i];
if (hAligns.length == headerRow.length) {
HorizontalAlignment hAlign = hAligns[j];
properties.put(CellUtil.ALIGNMENT, hAlign); // horizontal alignment
}
}
if (verticalAlignments.length == headers.length) {
VerticalAlignment[] hAligns = verticalAlignments[i];
if (hAligns.length == headerRow.length) {
VerticalAlignment vAlign = hAligns[j];
properties.put(CellUtil.VERTICAL_ALIGNMENT, vAlign); // vertical alignment
}
}
if (wrapTexts.length == headers.length) {
Boolean[] isWrapTexts = wrapTexts[i];
if (isWrapTexts.length == headerRow.length) {
Boolean isWrapText = isWrapTexts[j];
properties.put(CellUtil.WRAP_TEXT, isWrapText); // wrap text
}
}
CellUtil.setCellStyleProperties(cell, properties); //do using CellUtil for **add** new properties to already applied cell styles
j++;
}
i++;
}
// set header merged regions
for (int[] mergedRegion : headerMergedRegions) {
if (mergedRegion.length == 4) {
sheet.addMergedRegion(new CellRangeAddress(mergedRegion[0], mergedRegion[1], mergedRegion[2], mergedRegion[3]));
}
}
// draw header borders
propertyTemplate.drawBorders(new CellRangeAddress(0, headers.length-1, 0, headers[0].length-1), BorderStyle.MEDIUM, IndexedColors.WHITE.getIndex(), BorderExtent.ALL); //since we have merged regions we can simply drawing all borders here
// input and format row headers
for (String quarter : quarters) {
Row row = sheet.createRow(rowIdx++);
Cell cell = row.createCell(0); // quarter in column 0 (A)
cell.setCellValue(quarter);
CellUtil.setVerticalAlignment(cell, VerticalAlignment.TOP); // quarter cells are top aligned
for (String subcategory : subcategories) {
cell = row.createCell(1); // subcategory in column 1 (B)
cell.setCellValue(subcategory);
sheet.addMergedRegion(new CellRangeAddress(rowIdx, rowIdx, 1, 2));
row = sheet.createRow(rowIdx++);
}
rowIdx--;
sheet.addMergedRegion(new CellRangeAddress(rowIdx-subcategories.length, rowIdx-1, 0, 0));
}
rowIdx -= quarters.length * subcategories.length; // reset the rowIdx
// input values - number formats came from default column style
for (Double[] rowValues : values) {
Row row = sheet.getRow(rowIdx++); //get the row instead of creating it
colIdx = 3; // values are from column 3 (D) on
for (Double value : rowValues) {
Cell cell = row.createCell(colIdx++);
cell.setCellValue(value);
cell.setCellStyle(getPreferredCellStyle(cell));
}
}
// draw data borders
propertyTemplate.drawBorders(new CellRangeAddress(headers.length, headers.length+values.length-1, 0, headers[0].length-1), BorderStyle.MEDIUM, IndexedColors.LIGHT_ORANGE.getIndex(), BorderExtent.ALL); //since we have merged regions we can simply drawing all borders here
//apply the PropertyTemplate borders
propertyTemplate.applyBorders(sheet);
workbook.write(fileout);
}
}
}

How to change the pivot table style from default blue to other colors using apache-poi

When i create a pivot table using the below code, it comes with some default template style(blue). How to change this default style of pivot table using apache-poi library
pivotTable = sheet2.createPivotTable(aref, new CellReference("A4"), sheet1);
What I want.
What i am able to generate through code
XXSPivotTable is using named style PivotStyleLight16 per default. See setDefaultPivotTableDefinition.
There is no method for changing this in high level XSSF classes until now. Bu we can get the underlying low level CTPivotTableStyle form the CTPivotTableDefinition got via XSSFPivotTable.getCTPivotTableDefinition. Then we can use CTPivotTableStyle.setName to set another named style:
pivotTable.getCTPivotTableDefinition().getPivotTableStyleInfo().setName("PivotStyleMedium7");
Complete example:
import java.io.FileOutputStream;
import org.apache.poi.ss.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.xssf.usermodel.*;
class CreatePivotTableStyle {
public static void main(String[] args) throws Exception {
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {
Sheet pivotSheet = workbook.createSheet("Pivot");
Sheet dataSheet = workbook.createSheet("Data");
Row row;
Cell cell;
Object[][] data = new Object[][]{
new Object[]{"Name", "Count"},
new Object[]{"A", 2d},
new Object[]{"B", 4d},
new Object[]{"A", 1d},
new Object[]{"B", 7d}
};
for (int r = 0; r < data.length; r++) {
row = dataSheet.createRow(r);
Object[] rowData = data[r];
for (int c = 0; c < rowData.length; c++) {
cell = row.createCell(c);
if (rowData[c] instanceof String) {
cell.setCellValue((String)rowData[c]);
} else if (rowData[c] instanceof Double) {
cell.setCellValue((Double)rowData[c]);
}
}
}
AreaReference arerReference = new AreaReference("A1:B5", SpreadsheetVersion.EXCEL2007);
XSSFPivotTable pivotTable = ((XSSFSheet)pivotSheet).createPivotTable(arerReference, new CellReference("A4"), dataSheet);
pivotTable.addRowLabel(0);
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1, "Sum of count");
pivotTable.getCTPivotTableDefinition().getPivotTableStyleInfo().setName("PivotStyleMedium7");
workbook.write(fileout);
}
}
}
Names of possible named styles can be got from Excels GUI in PivotTable Tools tab - Design.

How to merge cells to the last row in poi

I am creating a workbook using apache poi where i am trying to merge a particular cell to the end of the output.I am using mergeRegion function and cell is merging but, that cell is not merging to the end of the row , it is always ending one line before ,
i am attaching the screen here merged cell
I want the cell to be merged properly, i am posting my code here
for(MarshActiveUser marshActiveUser : listOfMarshUser){
/***/
sheet.addMergedRegion(new CellRangeAddress(
j, //first row (0-based)
j, //last row (0-based)
18, //first column (0-based)
20 //last column (0-based)
));
/***/
int columnNo = 0;
row = sheet.createRow(j+1);
cell = row.createCell(columnNo);
cell.setCellValue(new HSSFRichTextString(String.valueOf(row.getRowNum())));
lockedCellStyle.setFont(hSSFFont);
sheet.autoSizeColumn(0);
cell.setCellStyle(lockedCellStyle);
columnNo = 1;
cell = row.createCell(columnNo);
if(null != marshActiveUser.getFistName()){
cell.setCellValue(new HSSFRichTextString(marshActiveUser.getFistName()));
lockedCellStyle.setFont(hSSFFont);
sheet.autoSizeColumn(1);
cell.setCellStyle(lockedCellStyle);
}else{
cell.setCellValue(new HSSFRichTextString(" "));
cell.setCellStyle(lockedCellStyle);
}
I have tried to start from rowCount +1 but that is not allowed in code , please help me .Thanks in advance.
There is a problem with rowCount increment. Pre incrementing the row count is skipping your last row for merging. Changed it to post increment rowcount++ and its working as expected.
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.CellRangeAddress;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
public class SimpleExcelWriterExample {
public static void main(String[] args) throws IOException {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Java Books");
Object[][] bookData = {
{"Head First Java", "Kathy Serria", 79},
{"Effective Java", "Joshua Bloch", 36},
{"Clean Code", "Robert martin", 42},
{"Thinking in Java", "Bruce Eckel", 35},
};
int rowCount = 1;
for (Object[] aBook : bookData) {
/***/
sheet.addMergedRegion(new CellRangeAddress(
rowCount, //first row (0-based)
rowCount, //last row (0-based)
3, //first column (0-based)
5 //last column (0-based)
));
/***/
Row row = sheet.createRow(rowCount++);
int columnCount = 0;
for (Object field : aBook) {
Cell cell = row.createCell(++columnCount);
if (field instanceof String) {
cell.setCellValue((String) field);
} else if (field instanceof Integer) {
cell.setCellValue((Integer) field);
}
}
}
try{
FileOutputStream outputStream = new FileOutputStream("D://JavaBooks.xls");
workbook.write(outputStream);
}catch(Exception e){}
}}
Output:

Categories

Resources