I'm using Java and OpenXLS to write out an Excel spreadsheet. I want to set a formula for a cell but I haven't got a clue how to do it. Can anybody help me, please? :)
(Can't tag this with "openxls" because I'm a new user...)
I don't know about OpenXLS, but it's easy to do with Andy Khan's JExcel. I'd recommend trying it. I think it's far superior to POI; I'm betting that it's better than OpenXLS as well.
OpenXLS support very well formulas. Look at this example.
I put a value in the columns A and B of a sheet named "testSheet". In the column C of the same sheet I put the result of SUM (A+B).Don't forget to initialise the column C else you will have a CellNotFoundException
WorkBookHandle workbook = new WorkBookHandle();
workbook.createWorkSheet("testSheet");
WorkSheetHandle sheet = workbook.getWorkSheet("testSheet");
for (int i=1 ;i<=10; i++)
{
sheet.add(10*i, "A"+i);
sheet.add(15*i, "B"+i);
CellHandle cx = sheet.add(0,"C"+i);
cx.setFormula("=SUM(A"+i+":B"+i+")");
}
I hope that that this example will help other people.
Ultimately it turned out that OpenXLS doesn't support formula cells. They are included in the paid for version, though...
You can set the formula String directly on the cell in the Worksheet:
CellHandle cell = ws.add( "=SUM(A1:A3)", "A5" );
This adds the SUM(A1:A3) formula in cell A5. Any Cell set with a String value that is prefixed with '=' is considered a Formula.
Updates and maintenance are now happening on github (search for openxls).
Related
I've been searching around a lot for this but couldn't find a solution. Hope someone can help me here.
I am using Apache POI to create a simple tool. Formulas will be inputted by user, and the result will be written on file. Im stuck at extending/filling the formula.
Suppose you have a simple excel formula:
IF(A2=B2,True,False)
A drag downwards on excel would result in:
IF(A2=B2,True,False)
IF(A3=B3,True,False)
IF(A4=B4,True,False)
IF(A5=B5,True,False)
. .
.
Now I want to do the same in my program. I will know which row to end. i just can't get the row index to increment. I have already done it manually (writing formula in program), but now I need to use this when formula is passed by user.
I have something like this for the manual part:
for (int ind = 2; ind < rownumb ; ind++)
{
sheet.getRow(i).createCell(12).setCellFormula("IF(K" + ind + "=L" + ind + ",FALSE,TRUE)");
}
Now the user will input:
=IF(K=L, False, True) OR =IF(K0=L0, False, True)
I want to add this formula auto-filling (incrementing) all the way till rownumb. How can I do this?
If there is no direct way, can someone suggest some other approach, however the requirement is that the formula will be passed by user.
Thanks.
Excel does not store it's function "in a sheet's cell" but as a VBA function. In order to be able to properly utilize excel function yourself you will need to emulate that. Check this article about user defined functions, this might get you going.
I'm having a problem where I need to reference the parent cell. So say A1's formula is "=B1", and B1's formula is "=C1". I need to compress A1's formula down to "=C1". I'm not sure if there is a way to do this in excel, or if there is a way to do this Apache POI. I have looked around, but can't really seem to find a solution to this. Does anyone know how to do this in excel or with the POI api?
In your Sample running this would give you the results you asked for.
Sub GetLastPrecedent()
Dim pres As Range
Dim TestCell As Range
Set TestCell = Range("A1")
'Set pres to all cells that are used in getting the value of TestCell
'This includes all precedents of precedents
Set pres = TestCell.Precedents
'This will return the absolute precedent of the ones returned
Set pres = pres.Cells(pres.Rows.Count, pres.Columns.Count)
'This will set the formula in TestCell to use the absolute address
TestCell.Formula = "=" & pres.Address
End Sub
I hope this can at least help guide you to what you are looking for. More info will result in a better answer. Remember if you have complex formula that reference many cells this will become very dangerous and complicated. I only provide this sample based on the information given as a way to help guide you.
Using Apache POI, I'm able to find a named range:
XSSFName[] ranges = new XSSFName[workbook.getNumberOfNames()];
for (int i = 0; i < _wb.getNumberOfNames(); i++)
ranges[i] = workbook.getNameAt(i);
With that, I'm able to cell an AreaReference:
AreaReference area = new AreaReference(ranges[0].getRefersToFormula());
And then finally I can get all the cells within that range:
CellReference[] cells = area.getAllReferencedCells();
That all works just fine. Burt I have a use case where I have to redefine the area that the range covers. Is there a way to do that? I notice that the range.getRefersToFormula() method return a String, something like MySheet!$A$1:$B$8. There is a range.setRefersToFormula(String formula), but I've got to believe there's a way other than resorting to writing an excel range formula parser on my own. Is there no way to generate an AreaReference with a set to Cell references of something more type-safe? Do I actually have to generate a String to represent the new range? I would think there would be API somewhere to help me with this but I can't seem to find it.
Update
I found some API, but it doesn't seem to work, at least it doesn't save properly. Here's what I did.
AreaReference newArea = new AreaReference(firstCell, lastCell);
ranges[0].setRefersToFormula(newArea.formatAsString())
It seems to set the formula correctly, but when I stream the workbook back out to disk, the range is completely wrong.
you can update the existing Reference and set it as per your requirement.
Suppose the reference contains TestSheet!$A$1:$B$8and you want to change it to MySheet!$B$5:$C$12
For any cell, say "B5", at runtime,
cell.getReference();
will give you cell reference (like in example... it will return you "B5")
char startCellColRef = cell.getReference().toString().charAt(0);
will give you the Column Reference (will give you "B" if the current cell is B5). Now
int startCellRowRef = cell.getReference().toString().charAt(1);
will give you Row Index (will give you "5" if the current cell is B5).
By the same way you can get your start and end cell references (say B5 and C12).
Now comes how can I update the existing references. Just update its value with newly created reference string
Name reference = wb.getName("NameReferenceInExcelSheet");
referenceString = sheetName+"!$"+startCellColRef+"$"+startCellRowRef+":$"+endCellColRef+"$"+endCellRowRef;
reference.setRefersToFormula(referenceString);
I'm generating an excel file using Apache POI 3.8 , and have the need to replicate some existing row n° times.
This because I have some complex formula which I use as a template to create new lines, replacing cell indexes with regexps.
The problem is that performance are awful, it takes 2h to generate some 4000 rows.
I've pinpointed the problem to be not in the regexp part, as I initially thought, but in the duplication of formula cells.
I actually use this to replicate formula cells:
case Cell.CELL_TYPE_FORMULA:
newCell.setCellType(oldCell.getCellType());
newCell.setCellFormula(oldCell.getCellFormula());
break;
If I copy the formula as text like this:
case Cell.CELL_TYPE_FORMULA:
newCell.setCellType(Cell.CELL_TYPE_STRING);
newCell.setCellValue("="+oldCell.getCellFormula());
break;
it's instead pretty fast, even with my regexp in place.
Anyway, this is an imperfect solution, because the formula has english keywords (ie IF()), when I need to write in italian format.
More, cells with formula inserted like that need to be forcefully re-evaluated in excel with something like "replace all -> '=' with '='".
The problem seems to rely in the setCellFormula(), because of the HSSFFormulaParser.parse().
What's strange, is that parsing time seems to grow exponentially:
100 rows -> 6785ms
200 rows -> 23933ms
300 rows -> 51388ms
400 rows -> 88586ms
What it seems, is that each time I copy a formula, the POI library re-evaluates or re-parses or re-something all preceding rows.
Do anyone know how can solve this problem?
Thanks in advance.
Oh my...I think I found it...
Original was:
// If the row exist in destination, push down all rows by 1 else create a new row
if (newRow != null) {
worksheet.shiftRows(destinationRowNum, worksheet.getLastRowNum(), 1);
} else {
newRow = worksheet.createRow(destinationRowNum);
}
I've commented everything leaving only
newRow = worksheet.createRow(destinationRowNum);
And now I'm down to 60sec to process all rows!
Probably, there's some dirt in my template which was causing POI to shift everything at each iteration.
I'm trying to use POI XSSF to evaluate some Excel formulas.
The values do not have to be saved, and I may have to calculate many formulas, so I'm trying to do it all in the same cell.
The problem is that the cell value seems to get stuck on the first formula entered even after I recalculate
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
XSSFCell formulaCell = row.createCell(6);
formulaCell.setCellFormula("Date(2011,10,6)");
CellValue cellValue = evaluator.evaluate(formulaCell);
System.out.println(cellValue.getNumberValue());
formulaCell.setCellFormula("Date(1911,3,4)");
cellValue = evaluator.evaluate(formulaCell);
System.out.println(cellValue.getNumberValue());
This outputs 40822.0
40822.0 (excel equivalent of 10/6/2011) both times instead of reevaluating to the new formula.
If you use the formulaEvaluator more than once, you need this line in between uses, or else it uses the same result each time.
formulaEvaluator.clearAllCachedResultValues()
The FormulaEvaluator caches cell calculated values to speed up processing. If you perform cell updates after creating the evaluator, then you need to tell it!
See the FormulaEvaluator documentation for more details. For you case, try:
formulaCell.setCellFormula("Date(1911,3,4)");
evaluator.notifySetFormula(formulaCell);
cellValue = evaluator.evaluate(formulaCell);
System.out.println(cellValue.getNumberValue());
You can use following steps to get your work done. These are two solutions out of which you can make use of any one function. It evaluates the complete workbook so whatever formula you use would get evaluated. Hope this helps.
1) evaluator.evaluateAll();
2) XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);