Optimize writing ods files with simple-odf - java

This is my code to write my file:
SpreadsheetDocument ods = SpreadsheetDocument.newSpreadsheetDocument();
Table table = Table.newTable(ods, 4000, 20, 0, 0);
table.setTableName("foo");
Border border = new Border(Color.BLACK, 1, StyleTypeDefinitions.SupportedLinearMeasure.PT);
Font font = new Font("Arial", FontStyle.BOLD, 7, Color.BLACK);
List<Row> rows = table.getRowList();
for (Row r : rows) {
for (int a = 0; a < 20; a++) {
Cell cell = r.getCellByIndex(a);
cell.setStringValue("Foo " + a);
cell.setBorders(CellBordersType.ALL_FOUR, border);
cell.setCellBackgroundColor(Color.valueOf("#A5A5A5"));
cell.setFont(font);
cell.setHorizontalAlignment(HorizontalAlignmentType.CENTER);
}
}
ods.save("K://foo.ods");
In this code I set the style at the cell level. To optimize the writing I want to know if there is any way to do for row or table level. Or create a style for border, font, size, etc ... in the document and set style with function setCellStyleName. I can do something like this?
The reason is because I get this error:
java.lang.OutOfMemoryError: Java heap space at
java.util.ArrayList.iterator(ArrayList.java:814) at
sun.nio.ch.WindowsSelectorImpl.updateSelectedKeys(WindowsSelectorImpl.java:496)
at
sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:172)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:87) at
sun.nio.ch.SelectorImpl.select(SelectorImpl.java:98) at
org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:1050)
at java.lang.Thread.run(Thread.java:745)
If I delete the format (border, font ...), I can write more rows.
If I open the content.xml, I can see that I have many defined styles that are equal.
I'm using this version:
<dependency>
<groupId>org.apache.odftoolkit</groupId>
<artifactId>simple-odf</artifactId>
<version>0.7-incubating</version>
</dependency>

Here is the sample code of apply ODF style to cell. I cannot find a easy solution to create style. What I do is createing a ods file, check the child element of office:automatic-styles in content.xml then convert it to java code.
SpreadsheetDocument ods = SpreadsheetDocument.newSpreadsheetDocument();
Table table = Table.newTable(ods, 4000, 20, 0, 0);
table.setTableName("foo");
//create style
OdfOfficeAutomaticStyles astyles = ods.getContentDom().getOrCreateAutomaticStyles();
StyleStyleElement ele = astyles.newStyleStyleElement(OdfStyleFamily.TableCell.getName(), "myss");
StyleTableCellPropertiesElement styleTableCellPropertiesElement = ele.newStyleTableCellPropertiesElement();
styleTableCellPropertiesElement.setFoBackgroundColorAttribute("#A5A5A5");
styleTableCellPropertiesElement.setFoBorderAttribute("1.0pt solid #000000");
ele.newStyleParagraphPropertiesElement().setFoTextAlignAttribute(HorizontalAlignmentType.CENTER.toString());
StyleTextPropertiesElement styleTextPropertiesElement = ele.newStyleTextPropertiesElement(null);
styleTextPropertiesElement.setStyleFontNameAttribute("Arial");
styleTextPropertiesElement.setFoFontSizeAttribute("7.0pt");
styleTextPropertiesElement.setFoColorAttribute(Color.BLACK.toString());
styleTextPropertiesElement.setFoFontWeightAttribute("bold");
List<Row> rows = table.getRowList();
for (Row r : rows) {
for (int a = 0; a < 10; a++) {
Cell cell = r.getCellByIndex(a);
cell.setStringValue("Foo " + a);
cell.setCellStyleName("myss");
}
}

Related

Select specific range/scope of a pivot table to apply format on (Aspose.Cells for Java)

Is there an equivalent of this VBA function PivotTable.PivotSelect in Aspose.Cells product ?
I am looking for a way to create a border on a whole selection of cells containing specific data field values, or on a specific scope as you prefer.
The VBA macro to perform this action is the following, by giving only the data field name parameter :
v_wbx.Sheets(v_SheetName).**PivotTables(v_CurrentPivotName).PivotSelect **DataFieldName**, xlDataAndLabel, True**
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
With Selection.Borders(xlEdgeLeft)
.LineStyle = xlContinuous
.Color = v_Color
.TintAndShade = 0
.Weight = v_Weight
End With
With Selection.Borders(xlEdgeTop)
.LineStyle = xlContinuous
.Color = v_Color
.TintAndShade = 0
.Weight = v_Weight
End With
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.Color = v_Color
.TintAndShade = 0
.Weight = v_Weight
End With
With Selection.Borders(xlEdgeRight)
.LineStyle = xlContinuous
.Color = v_Color
.TintAndShade = 0
.Weight = v_Weight
End With
Is this covered by Aspose.Cells ? I looked into documentation but haven't found any solution.
I'm aware that the "scope" selection is available with the Aspose conditional formatting, but here I want to create the border around the WHOLE selection of cells by specifying the data field name, and NOT use any Conditional Format rule.
This is done via VBA using this enum : https://learn.microsoft.com/en-us/office/vba/api/excel.xlptselectionmode and the function mentioned before.
I precise I'm using the trial version of the product to evaluate the range of features.
Please share your positive or negative feedback on this topic, thank you
You can format specific data area values in the Pivot Table via Aspose.Cells for Java. See the following example for your reference. You can apply formatting via both ways (i.e., use directly apply formatting and via pivot format condition).
e.g.
Sample code:
//Instantiating a Workbook object
Workbook workbook = new Workbook();
//Obtaining the reference of the newly added worksheet
int sheetIndex = workbook.getWorksheets().add();
Worksheet sheet = workbook.getWorksheets().get(sheetIndex);
Cells cells = sheet.getCells();
//Setting the value to the cells
Cell cell = cells.get("A1");
cell.setValue("Sport");
cell = cells.get("B1");
cell.setValue("Quarter");
cell = cells.get("C1");
cell.setValue("Sales");
cell = cells.get("A2");
cell.setValue("Golf");
cell = cells.get("A3");
cell.setValue("Golf");
cell = cells.get("A4");
cell.setValue("Tennis");
cell = cells.get("A5");
cell.setValue("Tennis");
cell = cells.get("A6");
cell.setValue("Tennis");
cell = cells.get("A7");
cell.setValue("Tennis");
cell = cells.get("A8");
cell.setValue("Golf");
cell = cells.get("B2");
cell.setValue("Qtr3");
cell = cells.get("B3");
cell.setValue("Qtr4");
cell = cells.get("B4");
cell.setValue("Qtr3");
cell = cells.get("B5");
cell.setValue("Qtr4");
cell = cells.get("B6");
cell.setValue("Qtr3");
cell = cells.get("B7");
cell.setValue("Qtr4");
cell = cells.get("B8");
cell.setValue("Qtr3");
cell = cells.get("C2");
cell.setValue(1500);
cell = cells.get("C3");
cell.setValue(2000);
cell = cells.get("C4");
cell.setValue(600);
cell = cells.get("C5");
cell.setValue(1500);
cell = cells.get("C6");
cell.setValue(4070);
cell = cells.get("C7");
cell.setValue(5000);
cell = cells.get("C8");
cell.setValue(6430);
PivotTableCollection pivotTables = sheet.getPivotTables();
//Adding a PivotTable to the worksheet
int index = pivotTables.add("=A1:C8", "E3", "PivotTable2");
//Accessing the instance of the newly added PivotTable
PivotTable pivotTable = pivotTables.get(index);
//Unshowing grand totals for rows.
pivotTable.setRowGrand(false);
//Dragging the first field to the row area.
pivotTable.addFieldToArea(PivotFieldType.ROW, 0);
//Dragging the second field to the column area.
pivotTable.addFieldToArea(PivotFieldType.COLUMN, 1);
//Dragging the third field to the data area.
pivotTable.addFieldToArea(PivotFieldType.DATA, 2);
pivotTable.refreshData();
pivotTable.calculateData();
/*
//Apply formatting to specific data area values via Pivot format condition.
PivotFormatConditionCollection pfcc = pivotTable.getPivotFormatConditions();
int pIndex = pfcc.add();
PivotFormatCondition pfc = pfcc.get(pIndex);
FormatConditionCollection fcc = pfc.getFormatConditions();
CellArea dataBodyRange = pivotTable.getDataBodyRange();
fcc.addArea(dataBodyRange);
int idx = fcc.addCondition(FormatConditionType.CELL_VALUE);
FormatCondition fc = fcc.get(idx);
fc.setFormula1("6000");
fc.setOperator(OperatorType.GREATER_OR_EQUAL);
//fc.getStyle().setBackgroundColor(com.aspose.cells.Color.getRed());
fc.getStyle().setBorder(BorderType.LEFT_BORDER, CellBorderType.THICK, com.aspose.cells.Color.getRed());
fc.getStyle().setBorder(BorderType.TOP_BORDER, CellBorderType.THICK, com.aspose.cells.Color.getRed());
fc.getStyle().setBorder(BorderType.RIGHT_BORDER, CellBorderType.THICK, com.aspose.cells.Color.getRed());
fc.getStyle().setBorder(BorderType.BOTTOM_BORDER, CellBorderType.THICK, com.aspose.cells.Color.getRed());
*/
///*
//Apply formatting directly to specific data fields.
CellArea dataArea = pivotTable.getDataBodyRange();
for(int dataRowNum = dataArea.StartRow; dataRowNum <= dataArea.EndRow;dataRowNum++){
for(int dataColNum = dataArea.StartColumn;dataColNum <= dataArea.EndColumn;dataColNum++){
cell = cells.get(dataRowNum,dataColNum);
int value = cell.getIntValue();
System.out.println(value);
if (value > 6000) {
Style style = cell.getStyle();
com.aspose.cells.Font font = style.getFont();
font.setColor(com.aspose.cells.Color.getBlue());
style.setBorder(BorderType.LEFT_BORDER, CellBorderType.THICK, com.aspose.cells.Color.getRed());
style.setBorder(BorderType.TOP_BORDER, CellBorderType.THICK, com.aspose.cells.Color.getRed());
style.setBorder(BorderType.RIGHT_BORDER, CellBorderType.THICK, com.aspose.cells.Color.getRed());
style.setBorder(BorderType.BOTTOM_BORDER, CellBorderType.THICK, com.aspose.cells.Color.getRed());
pivotTable.format(dataRowNum, dataColNum, style);
}
}
}
workbook.save("f:\\files\\out1.xlsx");
You may also post your queries in the dedicated forum.
PS. I am working as Support developer/ Evangelist at Aspose.

Can't change row text in .docx file once row is added to table

I have the problem with the following code:
XWPFTable table = <get table somehow>;
CTRow firstRow = table.getRow(0).getCtRow();
for (int i = 0; i < data.getRowCount(); i++) {
CTRow ctRow = (CTRow) firstRow.copy();
XWPFTableRow row = new XWPFTableRow(ctRow, table);
XWPFRun[] cellRuns = row.getTableCells()
.stream()
.map(c -> c.getParagraphs().get(0))
.map(p -> p.getRuns().isEmpty() ? p.createRun() : p.getRuns().get(0))
.toArray(XWPFRun[]::new);
for (int j = 0; j < cellRuns.length; j++) {
cellRuns[j].setText(data.getValueAt(i, j).toString(), 0);
}
table.addRow(row);
}
table.getRow(1).getTableCells()
.get(0).getParagraphs()
.get(0).getRuns()
.get(0).setText("FooBar", 0); //change text in some added row
This code is copying the first row of the table several times and then copying values from data. Works perfectly fine (except text style) except the last operator, which was supposed to change the text in some added table row. Also, the "FooBar" string doesn't even appear in document.xml of created WORD document. I failed to see any clues from debug, because it seems, that table.addRow(row); operator just copies row pointer to it's internal list of rows. Also, I didn't have problems with altering already existing rows. So do you have any ideas why this could happen?
To reproducing the problem do having a source.docx having a first table having at least two rows.
Then do running following code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
public class WordInsertTableRow {
static XWPFTableRow insertNewTableRow(XWPFTableRow sourceTableRow, int pos) throws Exception {
XWPFTable table = sourceTableRow.getTable();
CTRow newCTRrow = CTRow.Factory.parse(sourceTableRow.getCtRow().newInputStream());
XWPFTableRow tableRow = new XWPFTableRow(newCTRrow, table);
table.addRow(tableRow, pos);
return tableRow;
}
static void commitTableRows(XWPFTable table) {
int rowNr = 0;
for (XWPFTableRow tableRow : table.getRows()) {
table.getCTTbl().setTrArray(rowNr++, tableRow.getCtRow());
}
}
public static void main(String[] args) throws Exception {
XWPFDocument doc = new XWPFDocument(new FileInputStream("source.docx"));
boolean weMustCommitTableRows = false;
XWPFTable table = doc.getTableArray(0);
// insert new row, which is a copy of row 2, as new row 3:
XWPFTableRow sourceTableRow = table.getRow(1);
XWPFTableRow newRow3 = insertNewTableRow(sourceTableRow, 2);
// now changing something in that new row:
int i = 1;
for (XWPFTableCell cell : newRow3.getTableCells()) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
for (XWPFRun run : paragraph.getRuns()) {
run.setText("New row 3 run " + i++, 0);
}
}
}
System.out.println(newRow3.getCtRow()); // was changed
System.out.println(table.getRow(2).getCtRow()); // even this is changed
System.out.println(table.getCTTbl().getTrArray(2)); // but this was not changed, why not?
weMustCommitTableRows = true;
if (weMustCommitTableRows) commitTableRows(table); // now it is changed
FileOutputStream out = new FileOutputStream("result.docx");
doc.write(out);
out.close();
doc.close();
}
}
This code creates a copy of second row and inserts it as third row in the table. Then it does changing something in that new third row.
The issue ist, that the changings do appearing in low level CTRow of the row itself but do not appearing in low Level CTTbl of the table. For me this is not logically and I cannot get the reason of that. It looks as if the new CTRow elements are not part of the CTTbl at all. But they were added to it using ctTbl.setTrArray in XWPFTable.addRow. So I suspect there is something wrong with setTrArray in org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl. It seems updating the XML correctly but losing the object relations in the array (or list) of CTRows in CTTbl. But this is very hard to determining because of the kind of programming the org.openxmlformats.schemas classes. At least I was not able to do so. Maybe another of the professional and enthusiast programmers here may be able?
I am using the same approach for inserting rows having tthe same styling as a given source row. But after I have done this, I am setting boolean weMustCommitTableRows = true; and then I am doing if (weMustCommitTableRows) commitTableRows(table); before writing out the document. Then all changings will be committed.

Expanding an existing table in Excel using Apache POI

I've got an table in excel with formulae I would like to add data to.
My motivation for this is the fact that tables in excel can dynamically expand to the range of data you add to them, meaning that the formula rows automatically keep up with the amount of data rows.
I'm however having a hard time finding out if this is possible using apache-POI.
One thing I was going to try (see code below) was to expand the AreaReference of the table to cover the data, however both AreaReference(CR,CR2); (as used in this example) and AreaReference(CR,CR2, SpreadsheetVersion.EXCEL2007) (seen in the apache docs) give "constructor is undefined".
No idea what is causing that constructor error as I do have org.apache.poi.ss.util imported.
The other option on the apache docs AreaReference(java.lang.String reference) lets me compile and run but instead gives a "NoSuchMethod" error.
List<XSSFTable> tableList = spreadSheet.getTables();
CellReference CR = new CellReference(0, 0);
CellReference CR2 = new CellReference(5, 2);
AreaReference my_data_range = new AreaReference(CR,CR2);
tableList.get(0).setArea(my_data_range);
Any help will be appreciated.
The main problem using apache poi until now is that it is not ready to be used without having detailed knowledge about Microsoft Office as such and about the storage of Microsoft Office files. There are many things only half way ready and there are regressions often in new versions (bugs occur again which were solved already).
So your requirement: "Expanding an existing table in Excel using Apache POI" is not possible only simply using apache poi. One must know that Office Open XML files *.xlsx are simply ZIP archives which can be unzipped. And after unzipping we find /xl/tables/table1.xml for storage of the table. This XML we can analyzing and comparing it with XML which was created using Excel's GUI. So we can find problems which results from shortcomings of apache poi. Same is with the sheet's XML in /xl/tables/sheet1.xml.
Also we need to know that apache poi builds on the low level classes of ooxml-schemas. Partially we need using those classes because of the halfway readiness of apache poi. In the following example we need ooxml-schemas-1.4.jar additionally because apache poi's poi-ooxml-schemas-4.0.0.jar has not included org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableFormula until now. Unfortunately there is no documentation about ooxml-schemas public available. So we need downloading the sources and doing javadoc our own.
The following example works for me using apache poi 4.0.0. If you get problems while compiling or running, the reason might be that multiple different versions of apache poi jars are in class path while compile time and/or run time. Do not mix different apache poi versions. Also, as said already, my code needs the full jar of all of the schemas ooxml-schemas-1.4.jar.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.SpreadsheetVersion;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
class ExcelExpandingTable {
static void addRowToTable(XSSFTable table) {
int lastTableRow = table.getEndCellReference().getRow();
int totalsRowCount = table.getTotalsRowCount();
int lastTableDataRow = lastTableRow - totalsRowCount;
// we will add one row in table data
lastTableRow++;
lastTableDataRow++;
// new table area plus one row
AreaReference newTableArea = new AreaReference(
table.getStartCellReference(),
new CellReference(
lastTableRow,
table.getEndCellReference().getCol()
),
SpreadsheetVersion.EXCEL2007
);
// new table data area plus one row
AreaReference newTableDataArea = new AreaReference(
table.getStartCellReference(),
new CellReference(
lastTableDataRow,
table.getEndCellReference().getCol()
),
SpreadsheetVersion.EXCEL2007
);
XSSFSheet sheet = table.getXSSFSheet();
if (totalsRowCount > 0) {
//if we have totals rows, shift totals rows down
sheet.shiftRows(lastTableDataRow, lastTableRow, 1);
// correcting bug that shiftRows does not adjusting references of the cells
// if row 3 is shifted down, then reference in the cells remain r="A3", r="B3", ...
// they must be adjusted to the new row thoug: r="A4", r="B4", ...
// apache poi 3.17 has done this properly but had have other bugs in shiftRows.
for (int r = lastTableDataRow; r < lastTableRow + 1; r++) {
XSSFRow row = sheet.getRow(r);
if (row != null) {
long rRef = row.getCTRow().getR();
for (Cell cell : row) {
String cRef = ((XSSFCell)cell).getCTCell().getR();
((XSSFCell)cell).getCTCell().setR(cRef.replaceAll("[0-9]", "") + rRef);
}
}
}
// end correcting bug
}
// if there are CalculatedColumnFormulas do filling them to the new row
XSSFRow row = sheet.getRow(lastTableDataRow); if (row == null) row = sheet.createRow(lastTableDataRow);
int firstTableCol = table.getStartCellReference().getCol();
for (CTTableColumn tableCol : table.getCTTable().getTableColumns().getTableColumnList()) {
if (tableCol.getCalculatedColumnFormula() != null) {
int id = (int)tableCol.getId();
String formula = tableCol.getCalculatedColumnFormula().getStringValue();
XSSFCell cell = row.getCell(firstTableCol + id - 1); if (cell == null) cell = row.createCell(firstTableCol + id - 1);
cell.setCellFormula(formula);
}
}
table.setArea(newTableArea);
// correcting bug that Autofilter includes possible TotalsRows after setArea new
// Autofilter must only contain data area
table.getCTTable().getAutoFilter().setRef(newTableDataArea.formatAsString());
// end correcting bug
table.updateReferences();
}
public static void main(String[] args) throws Exception {
try (Workbook workbook = WorkbookFactory.create(new FileInputStream("SAMPLE.xlsx"));
FileOutputStream out = new FileOutputStream("SAMPLE_NEW.xlsx")) {
XSSFSheet sheet = ((XSSFWorkbook)workbook).getSheetAt(0);
XSSFTable table = sheet.getTables().get(0);
addRowToTable(table);
workbook.write(out);
}
}
}
The above was 2018. Now we have 2022.
Using current apache poi 5.2.2 the code may be like follows:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.SpreadsheetVersion;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
class ExcelExpandingTable {
static XSSFRow addRowToTable(XSSFTable table) {
int lastTableRow = table.getEndCellReference().getRow();
int totalsRowCount = table.getTotalsRowCount();
int lastTableDataRow = lastTableRow - totalsRowCount;
int firstTableCol = table.getStartCellReference().getCol();
// we will add one row in table data
lastTableRow++;
lastTableDataRow++;
// new table area plus one row
AreaReference newTableArea = new AreaReference(
table.getStartCellReference(),
new CellReference(
lastTableRow,
table.getEndCellReference().getCol()
),
SpreadsheetVersion.EXCEL2007
);
XSSFSheet sheet = table.getXSSFSheet();
if (totalsRowCount > 0) {
//if we have totals rows, shift totals rows down
sheet.shiftRows(lastTableDataRow, lastTableRow, 1);
//correct all sheet table-reference-formulas which probably got damaged after shift rows
for (CTTableColumn tableCol : table.getCTTable().getTableColumns().getTableColumnList()) {
if (tableCol.getCalculatedColumnFormula() != null) {
int id = (int)tableCol.getId();
String formula = tableCol.getCalculatedColumnFormula().getStringValue();
int rFirst = table.getStartCellReference().getRow() + table.getHeaderRowCount();
int rLast = table.getEndCellReference().getRow() - table.getTotalsRowCount();
int c = table.getStartCellReference().getCol() + id - 1;
sheet.getWorkbook().setCellFormulaValidation(false);
for (int r = rFirst; r <= rLast; r++) {
XSSFRow row = sheet.getRow(r); if (row == null) row = sheet.createRow(r);
XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
cell.setCellFormula(formula);
}
}
}
}
// if there are CalculatedColumnFormulas do filling them to the new row
XSSFRow row = sheet.getRow(lastTableDataRow); if (row == null) row = sheet.createRow(lastTableDataRow);
for (CTTableColumn tableCol : table.getCTTable().getTableColumns().getTableColumnList()) {
if (tableCol.getCalculatedColumnFormula() != null) {
int id = (int)tableCol.getId();
String formula = tableCol.getCalculatedColumnFormula().getStringValue();
XSSFCell cell = row.getCell(firstTableCol + id - 1); if (cell == null) cell = row.createCell(firstTableCol + id - 1);
cell.getSheet().getWorkbook().setCellFormulaValidation(false); // see https://bz.apache.org/bugzilla/show_bug.cgi?id=66039
cell.setCellFormula(formula);
}
}
// copy cell styles to the new row from the row above
row = sheet.getRow(lastTableDataRow); if (row == null) row = sheet.createRow(lastTableDataRow);
XSSFRow rowAbove = sheet.getRow(lastTableDataRow - 1); if (row == null) row = sheet.createRow(lastTableDataRow - 1);
for (CTTableColumn tableCol : table.getCTTable().getTableColumns().getTableColumnList()) {
int id = (int)tableCol.getId();
XSSFCell cellAbove = rowAbove.getCell(firstTableCol + id - 1);
if (cellAbove != null) {
XSSFCellStyle styleAbove = cellAbove.getCellStyle();
XSSFCell cell = row.getCell(firstTableCol + id - 1); if (cell == null) cell = row.createCell(firstTableCol + id - 1);
cell.setCellStyle(styleAbove);
}
}
// set new table area
table.setArea(newTableArea);
// update table references
table.updateReferences();
return sheet.getRow(lastTableDataRow);
}
public static void main(String[] args) throws Exception {
try (Workbook workbook = WorkbookFactory.create(new FileInputStream("SAMPLE.xlsx"));
FileOutputStream out = new FileOutputStream("SAMPLE_NEW.xlsx")) {
XSSFSheet sheet = ((XSSFWorkbook)workbook).getSheetAt(0);
XSSFTable table = sheet.getTables().get(0);
XSSFRow row = addRowToTable(table);
workbook.write(out);
}
}
}
According to FAQ, this code needs poi-ooxml-full-5.2.2.jar instead of ooxml-schemas-1.4.jar now for run using apache poi 5.2.2.
Some bugs are fixed. But there is one new bug when using XSSFCell.setCellFormula when formula contains table references. But XSSFWorkbook.setCellFormulaValidation(false) avoids this.

iText column width wrong

Im using iText in android to build a pdf file with a table . It seems easy to do but the result is wrong. Help appreciated!
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(output));
Document documento = new Document(pdfDoc);
float[] columnWidths = new float[]{40, 160, 50, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25};
Table table = new Table(columnWidths);
table.setWidth(500);
com.itextpdf.layout.element.Cell cell = new com.itextpdf.layout.element.Cell(1, columnWidths.length).add("(Continuação)");
table.addHeaderCell(cell);
cell = new com.itextpdf.layout.element.Cell(1, columnWidths.length).add("Continua...");
table.addFooterCell(cell);
table.setSkipFirstHeader(true);
table.setSkipLastFooter(true);
Cell cellA;
for (int i = 0; i < 100; i++) {
cellA = new Cell(1, 1).add(String.valueOf(i+1));
cellA.setTextAlignment(TextAlignment.CENTER);
cellA.setWidth(40);
cellA.setFontSize(7);
table.addCell(cellA);
cellA = new Cell(1, 1).add("ALYNE BORGES MADEIRA");
cellA.setTextAlignment(TextAlignment.LEFT);
cellA.setWidth(160);
cellA.setFontSize(7);
table.addCell(cellA);
cellA = new Cell(1, 1).add("100.00");
cellA.setTextAlignment(TextAlignment.CENTER);
cellA.setWidth(50);
cellA.setFontSize(7);
table.addCell(cellA);
for (int j = 0; j < 10; j++) {
cellA = new Cell(1, 1).add("10.00");
cellA.setTextAlignment(TextAlignment.CENTER);
cellA.setWidth(25);
cellA.setFontSize(7);
table.addCell(cellA);
}
}
The problem is in the last column where width is not equal to prior 9.
Summary
If you are only using it to generate PDF tables instead of needing RTF and HTML output, then it might be better to use the PdfPTable class [Table is now unsupported] which is better supported and less prone to quirks (as explained here: PdfpTable vs. Table (vs. SimpleTable?)).
Sizing
If you use PdfPTable with setWidths(float[]) then you should be able to do absolute widths without needing to specify the width in each cell for code readability. (You can also use percentage widths, which, for a basic table, might be easier to get aligned properly on the page.)
Headers & Footers
Since you are using headers & footers, PdfPTable has setHeaderRows(int) and setFooterRows(int), but note that:
The number of footer rows are subtracted from the header rows. For example, for a table with two header rows and one footer row the code would be:
table.setHeaderRows(3);
table.setFooterRows(1);
PdfPCell Porting
Also note that PdfPCell has changed setTextAlignment to be setHorizontalAlignment.
Examples and Documentation
Some examples of using it are here (note the usage of setLockedWidth: https://developers.itextpdf.com/examples/tables-itext5/cell-and-table-widths
The JavaDoc for PdfPTable is here: http://itextsupport.com/apidocs/itext5/5.5.9/com/itextpdf/text/pdf/PdfPTable.html
And the JavaDoc for PdfPCell is here: http://itextsupport.com/apidocs/itext5/5.5.9/com/itextpdf/text/pdf/PdfPCell.html

Auto size height for rows in Apache POI

I am inputting values into a spreadsheet using Apache POI. These values have newlines, and I was able to use this code successfully:
CellStyle style = cell.getCellStyle()
style.setWrapText(true)
cell.setCellStyle(style)
Unfortunately, while the text is wrapping correctly, the rows are not always growing in height enough to show the content. How do I ensure that my rows are always the correct height?
currentRow.setHeight((short)-1)
Works for XSSFCell and Excel 2013
HSSFWorkbook workbook=new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("FirstSheet");
HSSFRow rowhead= sheet.createRow((short)0);
HSSFCellStyle style = workbook.createCellStyle();
style.setWrapText(true);
row.setRowStyle(style);
row.getCell(0).setCellStyle(style);
The above code will generate dynamic height of rows.
The only way I got this to work was write my own implementation to calculate the row height. The code is now released as the Taro project, so you could use that. It has numerous convenience methods to let you write an Excel file in far fewer lines of code.
If you prefer to put the implementation in your own code, you can find it in the SpreadsheetTab class. There is an autoSizeRow(int rowIndex) method half way down. It basically iterates down the row and for each cell finds the number of lines of text, then uses the font size to calculate the optimal cell height. It then sets the row height to the height of the tallest cell.
See all this link, which provides some code to manually calculate the correct height for a row, based on the column width and cell content. I've not personally tested it. Also pasted below for convenience:
// Create Font object with Font attribute (e.g. Font family, Font size, etc) for calculation
java.awt.Font currFont = new java.awt.Font(fontName, 0, fontSize);
AttributedString attrStr = new AttributedString(cellValue);
attrStr.addAttribute(TextAttribute.FONT, currFont);
// Use LineBreakMeasurer to count number of lines needed for the text
FontRenderContext frc = new FontRenderContext(null, true, true);
LineBreakMeasurer measurer = new LineBreakMeasurer(attrStr.getIterator(), frc);
int nextPos = 0;
int lineCnt = 0;
while (measurer.getPosition() < cellValue.length())
{
nextPos = measurer.nextOffset(mergedCellWidth); // mergedCellWidth is the max width of each line
lineCnt++;
measurer.setPosition(nextPos);
}
Row currRow = currSht.getRow(rowNum);
currRow.setHeight((short)(currRow.getHeight() * lineCnt));
// The above solution doesn't handle the newline character, i.e. "\n", and only
// tested under horizontal merged cells.
cell.getRow().setHeight((short) -1);
Worked for HSSFCell in apache poi 3.9 or above
It works in Excel 2010.
I set the limit of cell length of 50 characters
Row row = sheet.createRow(0);
CellStyle style = workbook.createCellStyle();
style.setWrapText(true);
if (data.length() > 50) {
for (int i = 1; i <= Math.abs(data.length() / 50); i++) {
data = data.substring(0, i * 50) + "\n" + data.substring(i * 50);
}
Cell cell = row.createCell(0);
row.setRowStyle(style);
cell.setCellStyle(style);
cell.setCellValue(data);
sheet.autoSizeColumn(0);
}
In my case a robust solution was to calculate the number of lines and set the row height to a multiple of the default row height:
int numberOfLines = cell.getStringCellValue().split("\n").length;
row.setHeightInPoints(numberOfLines*sheet.getDefaultRowHeightInPoints());
You can't adjust cell height directly.
But you can change the row's height
final HSSFSheet fs = wb.createSheet("sheet1");
final HSSFRow row0 = fs.createRow(0);
final HSSFCell cellA1 = row0.createCell(0);
row0.setHeight((short)700);
Row aitosize work for me:
cell.getRow().setHeight((short)0);
Here 0 for calculate autoheight.
Workaround for “LibreOffice Calc“ and “WPS Spreadsheet” with auto height for merged sells.
I add a column out to the right of a main document (In my case it was 32 column)
Set width as all merged cells with same text.
Set style WrapText to true
Set style to Align Top
Copy content which will be displayed in the merged cells
Set that column to be hidden
Set a row height = -1
A sample of code:
private void applyRowHightWorkaroundForMergedCells(HSSFCell cell0) {
HSSFSheet sheet = cell0.getSheet();
HSSFRow row = cell0.getRow();
String value = cell0.getStringCellValue();
HSSFCell cell = row.createCell(32);
sheet.setColumnWidth(32, 32000);
cell.getCellStyle().setWrapText(true);
cell.getCellStyle().setVerticalAlignment(VerticalAlignment.TOP);
cell.setCellValue(value);
sheet.setColumnHidden(32, true);
row.setHeight((short) -1);
}
//we can use column width for sheet
Ex: sheet.setColumnWidth(0, 2000);

Categories