Apache poi cell diagonal strikethrough - java

How can I strikethrough diagonally a cell in excel using Apache poi?
I want to get something like this:
I have tried:
cell.getCellStyle().setFillPattern(CellStyle.THIN_BACKWARD_DIAG)
but then the cell is having many diagonal lines instead of one from top right to bottom left.
Edit:
This is how I create the workbook:
Workbook workbook = new SXSSFWorkbook(SXSSFWorkbook.DEFAULT_WINDOW_SIZE);
Sheet sheet = workbook.createSheet("Test");
Then creating the columns and the rows, I don't see there any special to show.
Any idea what can I do?

Sorry for my previous answer, currently there is no diagonal border available readily in apache poi, though we can write our own custom method. You can use below method which will add a diagonal border in a cell.
public static void setDiagonal(StylesTable stylesSource, CTXf cellXtraFormating, ThemesTable theme) {
CTBorder ct = CTBorder.Factory.newInstance();
CTBorderPr pr = ct.addNewDiagonal();
ct.setDiagonalUp(true);
pr.setStyle(STBorderStyle.Enum.forInt(BorderFormatting.BORDER_THIN + 1));
int idx = stylesSource.putBorder(new XSSFCellBorder(ct, theme));
cellXtraFormating.setBorderId(idx);
cellXtraFormating.setApplyBorder(true);
}
call the above method in your class like this
CellStyle cs = workbook.createCellStyle();
StylesTable styleSource = ((XSSFWorkbook) workbook).getStylesSource();
ThemesTable theme = styleSource.getTheme();
CTXf cellXtraFormating = ((XSSFCellStyle) cs).getCoreXf();
-------your custom code---------
setDiagonal(styleSource, cellXtraFormating, theme);
cell.setCellStyle(cs);
I hope this answers your question

Related

Using cell styles provided by the ss model in Apache POI

I trying to make the code I already wrote for an XSSF workbook compatible to both xls and xlsx. Given below a piece of code as an example.
Workbook workbook = WorkbookFactory.create(new File("F:\\JavaEE\\test.xls"));
Sheet sheet = workbook.getSheetAt(0);
short cellBorderColour = IndexedColors.GREY_80_PERCENT.getIndex();
Font font = workbook.createFont();
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
font.setColor(IndexedColors.BLUE_GREY.index);
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
cellStyle.setAlignment(CellStyle.ALIGN_CENTER);
cellStyle.setFont(font);
cellStyle.setBorderLeft(CellStyle.BORDER_HAIR);
cellStyle.setLeftBorderColor(cellBorderColour);
cellStyle.setBorderTop(CellStyle.BORDER_HAIR);
cellStyle.setTopBorderColor(cellBorderColour);
cellStyle.setBorderRight(CellStyle.BORDER_HAIR);
cellStyle.setRightBorderColor(cellBorderColour);
cellStyle.setBorderBottom(CellStyle.BORDER_MEDIUM);
cellStyle.setBottomBorderColor(cellBorderColour);
Row row = sheet.createRow(1);
Cell cell = row.createCell(1);
sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 4));
borderRowCells(1, 4, row, cell, cellStyle);
cell.setCellValue("Value");
FileOutputStream fos = new FileOutputStream("F:\\JavaEE\\new_test.xls");
workbook.write(fos);
//Take care of exception handling and closing of the stream.
The utility method as used by the above code to border across merged cells.
private void borderRowCells(int from, int to, Row row, Cell cell, CellStyle cellStyle) {
for (int i = from; i <= to; ++i) {
cell = row.createCell(i);
cell.setCellStyle(cellStyle);
}
}
This code is meant to apply some borders in conjunction with other styles across some merged cells.
The border across merged cells is however, not applied correctly as can be seen in the following picture.
The borders are expected to be applied starting from B2 to E2. The actual border area however, covers only from C2 to E2
The cell value Value is also not aligned center which is specified in the cell style.
How to apply this border correctly across the merged cells along with center alignment?
Also the list of colours provided by IndexedColors.COLOR_NAME.getIndex() is very limited. The list is very unlikely to fulfill the real needs of colours in different cell styles.
Can we use RGB colours in the ss model as we do in the xssf model using XSSFColor as follows?
XSSFColor commonColor = new XSSFColor(new java.awt.Color(240, 240, 240));
Or even something better/different?
PS : I'm using Apache POI 3.10.1.

Using Apache POI to get Border & Fill Styles for new cell

Following the post made # POI Excel Merging Causing "Repaired Records: Format from /xl/styles.xml part (Styles)"
I have two excel files which are opening fine with styles and colors (In microsoft office 2010).
Iam merging both of those excel files using the code posted in the thread above.
The problem is with the styles (I created styles as below):
newCellStyle = newCell.getSheet().getWorkbook().createCellStyle();
newCellStyle.cloneStyleFrom(oldCellStyle);
styleMap.put(stHashCode, newCellStyle);
which has caused the styles problem "Repaired Records: Format from /xl/styles.xml part (Styles)"
after a fair amount of research what I learnt is the border and fill is causing the problem. Un setting these parameters has solved the problem. But as it states border and fill went missing.
Can some one throws idea around how to get the border and fill style from a cell and apply to a new cell ?
This appears to be a bug in Apache POI, #55800. The border ID and fill ID used in the "CoreXf" object aren't copied, causing the issue.
According to Comment 5 on that bug, it is possible to work around it by copying the fill and border attributes manually yourself.
The reason is it won't copy the XSSFCellFill and XSSFCellBorder. This also gives problem with borders. I have added a method in org.apache.poi.xssf.model.StylesTable which will help in creating a copy of workbook.
public void copyTo(StylesTable stylesTable){
stylesTable.numberFormats.clear();
stylesTable.fonts.clear();
stylesTable.fills.clear();
stylesTable.borders.clear();
stylesTable.styleXfs.clear();
stylesTable.xfs.clear();
stylesTable.dxfs.clear();
for(String str : numberFormats.values())
stylesTable.putNumberFormat(str);
for(XSSFFont font : fonts){
XSSFFont fontNew = new XSSFFont(font.getCTFont());
fontNew.registerTo(stylesTable);
}
for(XSSFCellFill fill : fills){
XSSFCellFill fillNew = new XSSFCellFill(fill.getCTFill());
stylesTable.putFill(fillNew);
}
for(XSSFCellBorder border : borders){
XSSFCellBorder borderNew = new XSSFCellBorder(border.getCTBorder());
stylesTable.putBorder(borderNew);
}
for(CTXf ctxf : styleXfs){
CTXf ctxfNew = (CTXf)ctxf.copy();
stylesTable.putCellStyleXf(ctxfNew);
}
for(CTXf ctxf : xfs){
CTXf ctxfNew = (CTXf)ctxf.copy();
stylesTable.putCellXf(ctxfNew);
}
for(CTDxf dxf : dxfs){
CTDxf dxfNew = (CTDxf)dxf.copy();
stylesTable.putDxf(dxfNew);
}
}
Following the post at https://issues.apache.org/bugzilla/show_bug.cgi?id=55800
As we are having trouble with border and fill
adding below piece of code worked like Charm
newCellStyle = newCell.getSheet().getWorkbook().createCellStyle();
newCellStyle.cloneStyleFrom(oldCellStyle);
// newCellStyle.getCoreXf().unsetBorderId();
// newCellStyle.getCoreXf().unsetFillId();
StylesTable newStylesSource = newCell.getSheet().getWorkbook().getStylesSource();
StylesTable oldStylesSource = oldCell.getSheet().getWorkbook().getStylesSource();
for (XSSFCellFill fill : oldStylesSource.getFills())
{
XSSFCellFill fillNew = new XSSFCellFill(fill.getCTFill());
newStylesSource.putFill(fillNew);
}
for (XSSFCellBorder border : oldStylesSource.getBorders())
{
XSSFCellBorder borderNew = new XSSFCellBorder(border.getCTBorder());
newStylesSource.putBorder(borderNew);
}
You could use the following code. I verified with .xlsx and I believe it would work with .xls also.
int stHashCode = oldCell.getCellStyle().hashCode();
CellStyle newCellStyle = newCell.getSheet().getWorkbook().createCellStyle();
newCellStyle.cloneStyleFrom(oldCell.getCellStyle());
newCell.setCellStyle(newCellStyle);
styleMap.put(stHashCode, newCellStyle);
if ( (newCell.getSheet().getWorkbook() instanceof XSSFWorkbook) && (oldCell.getSheet().getWorkbook() instanceof XSSFWorkbook) ){
StylesTable newStylesSource = ((XSSFWorkbook) newCell.getSheet().getWorkbook()).getStylesSource();
StylesTable oldStylesSource = ((XSSFWorkbook) oldCell.getSheet().getWorkbook()).getStylesSource();
for (XSSFCellFill fill : oldStylesSource.getFills()) {
XSSFCellFill fillNew = new XSSFCellFill(fill.getCTFill());
newStylesSource.putFill(fillNew);
}
for (XSSFCellBorder border : oldStylesSource.getBorders()) {
XSSFCellBorder borderNew = new XSSFCellBorder(border.getCTBorder());
newStylesSource.putBorder(borderNew);
}
}

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);

Changing size of cell comments in Apache POI

I use the following java code to successfully generate cell comments in Apache POI
public static void setComment(String text, Cell cell) {
final Map<Sheet, HSSFPatriarch> drawingPatriarches = new HashMap<Sheet, HSSFPatriarch>();
CreationHelper createHelper = cell.getSheet().getWorkbook().getCreationHelper();
HSSFSheet sheet = (HSSFSheet) cell.getSheet();
HSSFPatriarch drawingPatriarch = drawingPatriarches.get(sheet);
if (drawingPatriarch == null) {
drawingPatriarch = sheet.createDrawingPatriarch();
drawingPatriarches.put(sheet, drawingPatriarch);
}
Comment comment = drawingPatriarch.createComment(new HSSFClientAnchor(100, 100, 100, 100, (short)1, 1, (short) 10, 5));
comment.setString(createHelper.createRichTextString(text));
cell.setCellComment(comment);
}
I copied it from creating cell comments using HSSFClientAnchor in apache poi. Thank you Erik!
How can I change the size of the comment to 300 pixels width and 100 pixels height?
Thanks!
From what I can tell there's not an easy way since comment anchor points are specified by cell (column, row parameters) and offset into cell (dx, dy parameters). So you need to compute the width/height of the cells to figure out the second cell coordinates and then the offsets into that cell to make it exactly the pixel size you want.
Busy Developers' Guide to HSSF and XSSF Features
// When the comment box is visible, have it show in a 1x3 space
ClientAnchor anchor = factory.createClientAnchor();
anchor.setCol1(cell.getColumnIndex());
anchor.setCol2(cell.getColumnIndex()+1);
anchor.setRow1(row.getRowNum());
anchor.setRow2(row.getRowNum()+3);
Just change the values for setCol2 and setRow2.
You can assign a column width for any cell as follows:
sheet.setColumnWidth(0, 1000);

Apache POI Excel - how to configure columns to be expanded?

I am using Apache POI API to generate excel spreadsheet to output some data.
The problem I am facing is when the spreadsheet is created and opened, columns are not expanded so that some long text like Date formatted text is not showing up on first glance.
I could just double click the column border in excel to expand or drag the border to adjust the column width but there could be 20+ columns and there is no way I want to do that manually every time I open the spreadsheet :(
I found out (though could be wrong method) groupRow() and setColumnGroupCollapsed() might be able to do the trick but no luck. Maybe I'm using it in wrong way.
Sample Code snippet
Workbook wb = new HSSFWorkbook();
CreationHelper createHelper = wb.getCreationHelper();
//create sheet
Sheet sheet = wb.createSheet("masatoSheet");
//not really working yet.... :(
//set group for expand/collapse
//sheet.groupRow(0, 10); //just random fromRow toRow argument values...
//sheet.setColumnGroupCollapsed(0, true);
//create row
Row row = sheet.createRow((short)0);
//put a cell in the row and store long text data
row.createCell(0).setCellValue("Loooooooong text not to show up first");
When this spreadsheet is created, the "Looooooong text not to show up first" string is in the cell but since the column is not expanded only "Loooooooo" is showing up.
How can I configure it so that when I open my spreadsheet, the column is already expanded???
After you have added all your data to the sheet, you can call autoSizeColumn(int column) on your sheet to autofit the columns to the proper size
Here is a link to the API.
See this post for more reference
Problem in fitting the excel cell size to the size of the content when using apache poi
Tip : To make Auto size work , the call to sheet.autoSizeColumn(columnNumber) should be made after populating the data into the excel.
Calling the method before populating the data, will have no effect.
If you want to auto size all columns in a workbook, here is a method that might be useful:
public void autoSizeColumns(Workbook workbook) {
int numberOfSheets = workbook.getNumberOfSheets();
for (int i = 0; i < numberOfSheets; i++) {
Sheet sheet = workbook.getSheetAt(i);
if (sheet.getPhysicalNumberOfRows() > 0) {
Row row = sheet.getRow(sheet.getFirstRowNum());
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
int columnIndex = cell.getColumnIndex();
sheet.autoSizeColumn(columnIndex);
}
}
}
}
You can try something like this:
HSSFSheet summarySheet = wb.createSheet();
summarySheet.setColumnWidth(short column, short width);
Here params are:column number in sheet and its width
But,the units of width are pretty small, you can try 4000 for example.
For Excel POI:
sheetName.autoSizeColumn(cellnum);
sample code below
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("your sheet name");
HSSFRow row = sheet.createRow(0);
cell = row.createCell(0);
cell.setCellValue("A BIG NAME WITH AUTO SIZE FEATURE ENABLED");
//this is crucial
sheet.autoSizeColumn(0);
//argument must be cell number
cell = row.createCell(1);
cell.setCellValue("a big name without auto size feature enabled");
Check the output and go nuts :)
If you know the count of your columns (f.e. it's equal to a collection list). You can simply use this one liner to adjust all columns of one sheet (if you use at least java 8):
IntStream.range(0, columnCount).forEach(sheet::autoSizeColumn)
You can add this, after your loop.
for (int i = 0; i<53;i++) {
sheet.autoSizeColumn(i);
}
I use below simple solution:
This is your workbook and sheet:
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("YOUR Workshhet");
then add data to your sheet with columns and rows. Once done with adding data to sheet write following code to autoSizeColumn width.
for (int columnIndex = 0; columnIndex < 15; columnIndex++) {
sheet.autoSizeColumn(columnIndex);
}
Here, instead 15, you add the number of columns in your sheet.
Hope someone helps this.
You can use setColumnWidth() if you want to expand your cell more.
Its very simple, use this one line code
dataSheet.autoSizeColumn(0)
or give the number of column in bracket
dataSheet.autoSizeColumn(cell number )
You can wrap the text as well. PFB sample code:
CellStyle wrapCellStyle = new_workbook.createCellStyle();
wrapCellStyle.setWrapText(true);

Categories