Previously I was using POI 3.1.7 with setCellFormula without any issues. Now I've migrated to 4.1.1 and noticed that although the cell sets the formula correctly, it doesn't display any value (e.g the cell is set to "Accounting" format, the cell shows =PRODUCT(I4*L4), on screen it shows $ - . The code is as follow:
XSSFCell cell = null;
cell = row.createCell(12);
cell.setCellFormula("PRODUCT(I"+(processingRow+1)+",L"+(processingRow+1)+")");
cell.setCellStyle(getCellStyle("ACCOUNTING", sheet, true,true, false,false));
By the way, I'm using it on Excel 2013 (which I don't think should have any impact?). If I were to go into the formula cell and press enter at the end of the formula, the value will only then be displayed as it should be. Am I missing something?
You are correct. There is a retrograde from apache poi 3.17 to apache poi 4.x. The apache poi developer team has made the decision that formula cells always have a value. See CellBase.setCellFormula. That might be a correct decision.
But instead calculating the correct value then, they set it to 0. But 0 is a valuable value of it's own. The value 0 cannot be the placeholder for "not yet present".
In apache poi 3.17 the setCellFormula had only set the formula without a value. So Excel missed the value while parsing the sheet and calculated the value from the formula. So while creating a new workbook from scratch, formula evaluation is not necessary using apache poi 3.17.
Now using apache poi 4.x all formulas needs to be evaluated. Or setForceFormulaRecalculation must be set for the workbook. See Recalculation of Formulas.
Example:
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
class CreateExcelFormula {
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook();
FormulaEvaluator formulaEvaluator = workbook.getCreationHelper().createFormulaEvaluator(); // this is not necessary using apache poi 3.17
Sheet sheet = workbook.createSheet();
Row row = sheet.createRow(3);
Cell cell = row.createCell(8); cell.setCellValue(21.7);
cell = row.createCell(11); cell.setCellValue(20.0);
cell = row.createCell(0); cell.setCellFormula("PRODUCT(I4,L4)");
formulaEvaluator.evaluateFormulaCell(cell); // this is not necessary using apache poi 3.17
FileOutputStream out = new FileOutputStream("Excel.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
This solved the issue for me-
sheet.setForceFormulaRecalculation(true);
Related
I am trying to change the cell type from general to numeric of an excel sheet using Apache Poi. I have made the .xlsx file on my own from a .csv file using Poi itself. Now I need to change the cell_type of "E" and "F" column of the xlsx file to numeric. This is what I've tried:
FileInputStream fis = new FileInputStream(final_report_name);
XSSFWorkbook workBook = new XSSFWorkbook(fis);
XSSFSheet new_sheet = workBook.getSheetAt(0);
XSSFDataFormat format = workBook.createDataFormat();
XSSFCellStyle style = workBook.createCellStyle();
style.setDataFormat(format.getFormat("#"));
new_sheet.setDefaultColumnStyle(4, style); //These don't work
new_sheet.setDefaultColumnStyle(5, style); //They keep the cell type general
XSSFRow row = new_sheet.getRow(3);
Cell cell = row.getCell(5); //This changed the cell type to "#"
cell.setCellStyle(style); // But the number is still displayed as text
FileOutputStream fileOutputStream = new FileOutputStream(final_report_name);
workBook.write(fileOutputStream);
workBook.close();
The column styling does not work at all, and the cell styling worked, but the number is still displayed as text. I still need to manually go to the hovering icon next to it which says "The number in this cell is formatted as text or preceded by an apostrophe". then I need to click on "Convert to number" menu (see image). What could be the problem here and how do I achieve this?
Setting the cell style does not automatically change the cell type. The cell type depends on the cell content. Not even explicitly setting the cell type using Cell.setCellType will always automatically change the cell type if content don't match that type. So you need setting the cell content aka cell value correct.
There are various setCellValue methods in Cell. If setCellValue(java.lang.String value) or setCellValue(RichTextString value) is used, the cell type will always be text. Do using setCellValue(double value) for numeric values, setCellValue(boolean value) for boolean values (TRUE or FALSE) and one of the various setCellValue(DATETYPE) (setCellValue(java.util.Calendar value), setCellValue(java.time.LocalDateTime value), ...) for date values.
Am I doing it wrong, or is this a bug / limitation of POI?
I'm getting FormulaParseException: Cell reference expected after sheet name at index 8.
It works without the sheet qualifier, but then the formula will not work if copy pasted to another sheet.
And I need sheet-scoped names because multiple sheets defined the same names.
File file = new File(System.getProperty("user.home"), "Desktop/Test.xlsx");
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet1");
Name name = workbook.createName();
name.setNameName("NameForA1");
name.setSheetIndex(workbook.getSheetIndex(sheet));
name.setRefersToFormula("'Sheet1'!$A$1:$A$1");
Row row = sheet.createRow(0);
row.createCell(0).setCellValue("This is A1");
Cell b1 = row.createCell(1);
// b1.setCellFormula("'Sheet1'!NameForA1"); // throws exception
b1.setCellFormula("Sheet1!NameForA1"); // throws exception
// b1.setCellFormula("NameForA1"); // works
workbook.write(new FileOutputStream(file));
Desktop.getDesktop().open(file);
But I need:
Sorry, was a bug in 3.10.x. Works in 3.17.
Leaving the question. Maybe the example is useful to someone.
I am using apache-poi api (v3.9) in my project to process the excel template. I do update the all required cell values in all sheets of my excel document. I am using some complex formulas to calculate the double value for some cell.
I am facing the problem in reading the cell value of a cell having some complex formula. This complex formula works fine in excel sheet but return zero when I read it using poi.
Complex formula which I am using:
"=SUMPRODUCT(--('A-La-Carte'!$L$12:$L$100000=E129)*IF('A-La-Carte'!$K$12:$K$100000<>"-",'A-La-Carte'!$K$12:$K$100000,0)*IF(ISNUMBER(INT(LEFT('A-La-Carte'!$D$12:$D$100000,2))),12/INT(LEFT('A-La-Carte'!$D$12:$D$100000,2)),0))+(NOW()*0)"
If I change the above formula with some simple formula it works fine.
Below is the sample code which I used to read the cell value:
XSSFFormulaEvaluator.evaluateAllFormulaCells(workbook);
private String getCellValue(String cellRef,
XSSFWorkbook workbook,String sheetName) {
XSSFSheet xssfSheet = workbook.getSheet(sheetName);
CellReference cellReference = new CellReference(cellRef);
XSSFRow r = xssfSheet.getRow(cellReference.getRow());
if (r != null) {
XSSFCell c = r.getCell(cellReference.getCol());
if(c.getCellType()==XSSFCell.CELL_TYPE_NUMERIC)
return c.getNumericCellValue()+"";
else if((c.getCellType()==XSSFCell.CELL_TYPE_FORMULA)){
return c. getNumericCellValue()+"";
}
return c.getStringCellValue();
}
return null;
}
Can anybody tell me whats wrong with formula or API?
I have an excel sheet where additions have a red background, changes have a yellow background, and deletions are grey.
What I am hoping to do is read through the sheet, and based on the cell background color, perform the relevant database action.
Normally I would make each type of action in its own column, or add another column to determine action.
What options do I have for getting at the "format" that comes back in the spreadsheet object?
Thanks
Relying on cell color sounds brittle IMO. Assigning an explicit action column would be a better approach IMO.
That said, it is possible to access the color. However, there are no built in CF methods. You must dip into the underlying POI. First iterate through the cells in the spreadsheet:
<cfscript>
// get the sheet you want to read
cfSheet = SpreadSheetRead("c:/path/to/somefile.xlsx");
workbook = cfSheet.getWorkBook();
sheetIndex = workbook.getActiveSheetIndex();
sheet = workbook.getSheetAt( sheetIndex );
// process the rows and columns
rows = sheet.rowIterator();
while (rows.hasNext()) {
currentRow = rows.next();
// loop through populated cells in this row
cells = currentRow.cellIterator();
while (cells.hasNext()) {
currentCell = cells.next();
// .... get color
}
}
</cfscript>
Then for each cell, extract the style color. Not tested, but something like this should work. (See XSSFColor)
cellColor = currentCell.getCellStyle().getFillForegroundColorColor();
colorValue = cellColor.getARGBHex();
Update:
As #Sean mentioned in the comments, CF9 does not have the method above. Unfortunately getFillForegroundColorColor() and getARGBHex() were introduced sometime around 3.7, but CF is bundled with an earlier version: 3.5 (I think). So you must use the indexed color method instead (or upgrade the POI jars).
// only create once
colors = createObject("java", "org.apache.poi.ss.usermodel.IndexedColors");
//....
cellColor = currentCell.getCellStyle().getFillForegroundColor();
if (cellColor == colors.RED.getIndex()) {
WriteDump("This cell is RED. Do something...");
}
I am using XSSF to access the .xlsx format. Extracting row data and cell data is being done by
Row.getCell(1) // to get the first cell data.
Is there a way to access cells like
Row.getCell(A) or Row.getCell(AC).
This will be very helpfull for me to access columns.
Can any one tell me the way to do this?
I think the main class you're looking for is CellReference - it handles converting between user facing references such as "B2" into file format references like row=1,col=1 . There's a static method on there that handles your exact use case, convertColStringToIndex
For your use case, you'd want code something like
Cell c = row.getCell( CellReference.convertColStringToIndex("G") );
The question is regarding reaching out a cell using its references, if I am not wrong.
Sheet referenceSheet = workbook.getsheet("Sheet name your intrested in");
CellReference ref = new CellReference("C24");
Row row = referenceSheet.getRow(ref.getRow());
// null check for the row
if(row != null)
{
Cell cell = row.getCell(ref.getCol());
}
In this way we can refer a cell using its reference.