Using POI Set Cell Style Based on Cell Formula Result - java

I need some help on setting the cell style base on the cell value.
The code used to populate cell.
String totalvariationweightv1 = "J" + (x+1);
String totalvariationweightv2 = "L" + (x+1);
cell85014.setCellType(Cell.CELL_TYPE_FORMULA);
cell85014.setCellFormula("SUM(((" + totalvariationweightv2 + "-" + totalvariationweightv1 + ")/" + totalvariationweightv1 + ")*100)");
Then I need to color the field if it exceeds a certain value. Right now I just have alternating colors:
cell85014.setCellStyle((x%2)==0?stylefloatGray:stylefloat);
I cannot figure out how to get the cell value. Using getNumericValue returns 0.

Apache POI stores the formula, but it doesn't evaluate it automatically.
The Excel file format (both .xls and .xlsx) stores a "cached" result for every formula along with the formula itself. This means that when the file is opened, it can be quickly displayed, without needing to spend a long time calculating all of the formula results. It also means that when reading a file through Apache POI, the result is quickly available to you too!
After making changes with Apache POI to either Formula Cells themselves, or those that they depend on, you should normally perform a Formula Evaluation to have these "cached" results updated. This is normally done after all changes have been performed, but before you write the file out.
You must tell Apache POI to evaluate the formula separately.
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
// Set your cell formula here
switch (evaluator.evaluateFormulaCell(cell85014)) {
case Cell.CELL_TYPE_NUMERIC:
double x = cell85014.getNumericCellValue();
// Set cell style here, based on numeric value,
// as you already are doing in your code.
// Watch out for floating point inaccuracies!
break;
default:
System.err.println("Unexpected result type!");
break;
}

Related

Apache Poi cell not returning the correct value

I have a excel file with a cell that generates the number 3.69 (based on calculations from proceeding numbers)
However when pulling that number in java using
if (brightCell.getNumericCellValue()) > 0 )
{
double brightness = brightCell.getNumericCellValue();
return brightness;
}
I've also tried:
if (Double.parseDouble(brightCell.getStringCellValue()) > 0 )
{
double brightness = Double.parseDouble(brightCell.getStringCellValue());
return brightness;
}
brightCell is instantiated with :
brightCell = spreadsheet.getRow(new CellReference(brightString).getRow()).getCell(new CellReference(brightString).getCol());
brightString is String brightString = "BV29"
But with both solutions, brightness receives the value, 3.2133....
So thanks to #Igor I managed to figure it out but it led to more issues.
So the solution was creating an evaluator
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
evaluator.setIgnoreMissingWorkbooks(true); //if you need it
when you finish setting the required cells and want to evaluate.
evaluator.EvaluateAll();
The problem for me is I'm doing this multiple times and my 1st resut is correct but upon the second iteration it becomes skewed, and more skewed.
What I'm doing is setting various cells (via java) then before I retrieve the value for a cell (that contains a formula) I run EvaluateAll. Now, I'm not sure if I should be evaluating after EVERY change or after I make all my changes to the excel sheet (via java).
I can't evaluate a specific cell at a time because there's over 38 sheets with multitudes of formulas. So EvaluateAll is the best option for me
EDIT 26/10/2018*
So the issue was not clearing the cache after making inputs. The solution was after each input as specified in the javaDoc that:
Should be called whenever there are changes to input cells in the evaluated workbook.
Failure to call this method after changing cell values will cause incorrect behaviour
of the evaluate~ methods of this class
therefore after making an input on a cell you should call evaluator.clearAllCachedResultValues();

Apache POI formulas not evaluating

So I'm having some issues getting Apache POI to evaluate formulas.
Here's the code I call to evaluate formulas before writing:
complete.getCreationHelper().createFormulaEvaluator().evaluateAll();
complete.write(fileOut);
Here's the code I call to write to the cells being used (proving they're numbers):
try{
cell.setCellValue((Double)grid[i][j]);
}
catch(Exception e){
cell.setCellValue((String)grid[i][j]);
}
FYI: grid is a 2D Object array containing only entries of the type double and String.
Here's the formulas I'm trying to evaluate:
"=G13 - H13"
"=STDEV.P(C1:L1)"
"=I13/G13"
Any ideas why when I open up my final workbook in Excel the formulas arn't evaluated? Also, when I click on an unevaluated field and hit enter Excel will recognize the formula and evaluate it. In bulk this isn't practical, but I believe it demonstrates that the cells being used are the correct type. Could this be related to the formulas being of the String type?
EDIT:
OK, so looks like you're supposed to explicitly tell it you have a formula cell. Here's my modified code to do that:
try{
cell.setCellValue((Double)grid[i][j]);
}
catch(Exception e){
String val = (String) grid[i][j];
if (val != null && val.startsWith("=")){
val = val.replaceAll("=", "");
cell.setCellType(XSSFCell.CELL_TYPE_FORMULA);
cell.setCellFormula(val);
}
else{
cell.setCellValue(val);
}
}
Unfortunately you need to remove the equals sign (which is dumb) to pass formulas and then force it to reevaluate before saving (which is dumb). After trying to get it to reevaluate formulas it complained, however, saying:
Caused by:
org.apache.poi.ss.formula.eval.NotImplementedFunctionException:
STDEV.P
I'm imagining that this means Excel has implemented standard deviation calculations but POI hasn't caught up yet?
Try this:
XSSFFormulaEvaluator.evaluateAllFormulaCells(workbook);
or, if you are using xls
HSSFFormulaEvaluator.evaluateAllFormulaCells(hssfWorkbook)
You probably want to call this just before saving.

Set a cell styling to have numbers show as percentages Apache POI

I'm trying to have numbers display as percentages in my cell. So far the calculations seems to all be working but I cannot get the numbers displayed to be formatted as percentages I've tried two different ways so far.
CellValue cv = evaluator.evaluate(cell);
DecimalFormat df = new DecimalFormat("###.##%");
cell.setCellValue(df.format(Math.abs(cell.getNumericCellValue())));
This way basically evaluates the cell and then gives it a java decimalFormat and uses java to create the formatting and the just places the result into the cell. The second method uses a CellStyle to try and attempt it and it looks like this
CellStyle stylePercent = wb.createCellStyle();
stylePercent.setDataFormat(wb.createDataFormat().getFormat("0.000%"));
where I then places the values into the sheet and then apply the style to the cell.
Neither of these have worked for me always leaving the value of 0.5 as 0.5 instead of 50% or even giving it 0.5%, it always just remains the same as without the styling.
This is also how I am applying the style and my formula as well.
cell.setCellFormula(""+cellValue+"/(SUM(D"+(row.getRowNum()+1)+" + F"+(row.getRowNum()+1)+" + H"+(row.getRowNum()+1)+"+ J"+(row.getRowNum()+1)+" + L"+(row.getRowNum()+1)+"+ N"+(row.getRowNum()+1)+"+ P"+(row.getRowNum()+1)+"+ R"+(row.getRowNum()+1)+"+ T"+(row.getRowNum()+1)+"+ V"+(row.getRowNum()+1)+"+ X"+(row.getRowNum()+1)+")+ Z"+(row.getRowNum()+1)+")");
cell.setCellStyle(stylePercent);

POI: setCellType(Cell.CELL_TYPE_FORMULA) fails because of Cell.CELL_TYPE_ERROR

My Java application reads an xls file and presents it on a JTable. So far so good.
When I try to save my worksheet, I iterate over row,col in my JTable and:
String str = (String) Table.getValueAt(row, col);
HSSFRow thisrow = sheet.getRow(row);
HSSFCell thiscell = thisrow.getCell(col);
if(thiscell==null) thiscell = thisrow.createCell(col);
switch(inferType(str)) {
case "formula":
thiscell.setCellType(Cell.CELL_TYPE_FORMULA);
thiscell.setCellFormula(str.substring(1));
break;
case "numeric":
thiscell.setCellType(Cell.CELL_TYPE_NUMERIC);
thiscell.setCellValue(Double.parseDouble(str));
break;
case "text":
thiscell.setCellType(Cell.CELL_TYPE_STRING);
thiscell.setCellValue(str);
break;
}
But when I run over a cell which was originally a formula, say A1/B1, that is #DIV/0! at the moment, setCellType fails.
With much investigation I found out that when setCellType is called, it tries to convert the old content to the new type. BUT, this didn't seem a problem to me, since every table formula cell was already a formula in the xls. Hence, I am never actually changing types.
Even so, when I call setCellType(Cell.CELL_TYPE_FORMULA) on a cell that is already a formula, but it is evaluated to #DIV/0!, I get an conversion exception.
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Cannot get a numeric value from a error formula cell
at org.apache.poi.hssf.usermodel.HSSFCell.typeMismatch(HSSFCell.java:648)
at org.apache.poi.hssf.usermodel.HSSFCell.checkFormulaCachedValueType(HSSFCell.java:653)
at org.apache.poi.hssf.usermodel.HSSFCell.getNumericCellValue(HSSFCell.java:678)
at org.apache.poi.hssf.usermodel.HSSFCell.setCellType(HSSFCell.java:317)
at org.apache.poi.hssf.usermodel.HSSFCell.setCellType(HSSFCell.java:283)
Actually my only workaround is, before setCellType:
if(thiscell.getCachedFormulaResultType()==Cell.CELL_TYPE_ERROR)
thiscell = thisrow.createCell(col);
This IS working, but I lose the original layout of the cell, e.g. its colors.
How can I properly setCellType if the Cell is a formula with evaluation error?
I found this in the mailing list of poi-apache:
There are two possible scenarios when setting value for a formula
cell;
Update the pre-calculated value of the formula. If a cell contains formula then cell.setCellValue just updates the pre-calculated
(cached) formula value, the formula itself remains and the cell type
is not changed
Remove the formula and change the cell type to String or Number:
cell.setCellFormula(null); //Remove the formula
then cell.setCellValue("I changed! My type is CELL_TYPE_STRING now"");
or cell.setCellValue(200); //NA() is gone, the real value is 200
I think we can improve cell.setCellValue for the case (1). If the new
value conflicts with formula type then IllegalArgumentException should
be thrown.
Regards, Yegor
Still, it does feel like a workaround to me. But everything is now working.
cell.setCellFormula(null) before any setCellType should prevent conversion failure, because the first will discard the cached content.

Apache POI Color cell with formula

I want create a excel with Apache POI in java and I must insert in a cell a formula: A3=B3+C3.
Is possible to insert another formula in A3 that color the cell if his value is> 0?
I use Apache POI 2.5.1
You will need a conditional formatting.
From this document:
// Define a Conditional Formatting rule, which triggers formatting
// when cell's value is greater or equal than 100.0 and
// applies patternFormatting defined below.
HSSFConditionalFormattingRule rule = sheet.createConditionalFormattingRule(
ComparisonOperator.GE,
"100.0", // 1st formula
null // 2nd formula is not used for comparison operator GE
);
// Create pattern with red background
HSSFPatternFormatting patternFmt = rule.cretePatternFormatting();
patternFormatting.setFillBackgroundColor(HSSFColor.RED.index);
// Define a region containing first column
Region [] regions =
{
new Region(1,(short)1,-1,(short)1)
};
// Apply Conditional Formatting rule defined above to the regions
sheet.addConditionalFormatting(regions, rule);
which creates a cell with a red background for values >= 100. Which is almost what you want :-)

Categories

Resources