Java 8 and Apache POI 4.1.x here. I have some Java code that writes a list of objects to an Excel file and its working perfectly fine, with the exception of some color-based cell styles I'm trying to apply:
public void applyPriceListDataCellStyle(PriceListItem priceListItem, Cell cell) {
short colorIndex;
switch(priceListItem.getChangeType()) {
case ADDITION:
colorIndex = IndexedColors.YELLOW.getIndex();
break;
case DELETION:
XSSFColor purple = new XSSFColor(new java.awt.Color(120,81,169), new DefaultIndexedColorMap());
colorIndex = purple.getIndex();
break;
case PRICE_ADJUSTMENT_INCREASE:
colorIndex = IndexedColors.RED.getIndex();
break;
case PRICE_ADJUSTMENT_DECREASE:
colorIndex = IndexedColors.GREEN.getIndex();
break;
default:
// NO_CHANGE (leave unstyled)
colorIndex = IndexedColors.WHITE.getIndex();
break;
}
Map<String,Object> cellProps = new HashMap<>();
cellProps.put(CellUtil.FILL_FOREGROUND_COLOR, colorIndex);
cellProps.put(CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
CellUtil.setCellStyleProperties(cell, cellProps);
}
Above, the applyPriceListDataCellStyle method is called after a Cell is created from a Row object. The cell instance is then passed into this method as an argument, along with my PriceListItem bean (which is the data I'm writing to each row in the Excel file).
The PriceListItem bean has a ChangeType property (enum) that dictates what color the cell should appear as in the final Excel file.
At runtime, I am calling this method on the cells of 5 different rows (so 5 different PriceListItems) of each ChangeType value, and I get output that looks like:
So:
The 1st row, which is a "NO_CHANGE" (which maps to IndexedColors.WHITE) works perfectly fine, as expected
The 2nd row, which is an "ADDITION" (which maps to IndexedColors.YELLOW) works perfectly fine, as expected
The 3rd row, which is a "DELETION" (which maps to my custom purple color) appears jet black instead -- wrong!
The 4th row, which is a "PRICE_ADJUSTMENT_INCREASE" (which maps to IndexedColors.RED) appears gray -- wrong!
The 5th row, which is a "PRICE_ADJUSTMENT_DECREASE" (which maps to IndexedColors.GREEN) appears a lighter shade of gray -- wrong!
Where am I going awry on setting the colors on the cells of these various rows?
The apache poi CellUtil only works using org.apache.poi.ss.*. It cannot work using a XSSFColor because org.apache.poi.ss.usermodel.CellStyle has no method to get/set fill foreground color from a XSSFColor. It only works using short color indexes from IndexedColors. Hence the black color, because in your code purple.getIndex() always returns 0. So if CellUtil shall be used, which is to recommend, then choose a color from IndexedColors instead of creating a custom color. There is IndexedColors.VIOLET for example.
But the other wrong cases are not reproducible for me. The following Minimal, Reproducible Example works for me as expected. It needs a price-list-template.xlsx having at least one worksheet.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellUtil;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PoiColors {
public static void main(String[] args) throws IOException {
List<PriceListItem> priceList = new ArrayList<>();
PriceListItem noChange = new PriceListItem();
noChange.modelNumber = "123";
noChange.price = BigDecimal.valueOf(1.99);
noChange.changeType = ChangeType.NO_CHANGE;
PriceListItem addition = new PriceListItem();
addition.modelNumber = "456";
addition.price = BigDecimal.valueOf(2.99);
addition.changeType = ChangeType.ADDITION;
PriceListItem deletion = new PriceListItem();
deletion.modelNumber = "789";
deletion.price = BigDecimal.valueOf(3.99);
deletion.changeType = ChangeType.DELETION;
PriceListItem increase = new PriceListItem();
increase.modelNumber = "234";
increase.price = BigDecimal.valueOf(4.99);
increase.changeType = ChangeType.PRICE_ADJUSTMENT_INCREASE;
PriceListItem decrease = new PriceListItem();
decrease.modelNumber = "345";
decrease.price = BigDecimal.valueOf(5.99);
decrease.changeType = ChangeType.PRICE_ADJUSTMENT_DECREASE;
priceList.add(noChange);
priceList.add(addition);
priceList.add(deletion);
priceList.add(increase);
priceList.add(decrease);
new PoiColors().exportPriceList(priceList, "acme.xlsx");
}
private void exportPriceList(
List<PriceListItem> priceList,
String targetAbsPath) throws IOException {
// set variables based on specified format
String templateName = "price-list-template.xlsx";
// load the template
InputStream inp = this.getClass().getClassLoader().getResource(templateName).openStream();
Workbook workbook = WorkbookFactory.create(inp);
Sheet sheet = workbook.getSheetAt(0);
workbook.setSheetName(workbook.getSheetIndex(sheet), "ACME");
// plug in the header/metadata info and format some headers so they get autosized properly
Row row2 = CellUtil.getRow(1, sheet);
Cell c2 = CellUtil.getCell(row2, 2);
c2.setCellValue("ACME");
// create the data rows and apply styling
// start at row #11 which is where data rows begin
int rowNum = 11;
// rip through the items and write them to the rows; apply styling as appropriate
for (PriceListItem priceListItem : priceList) {
Row nextRow = sheet.createRow(rowNum);
Cell changeType = nextRow.createCell(0);
changeType.setCellValue(priceListItem.changeType.name());
applyPriceListDataCellStyle(priceListItem, changeType);
Cell modelNumber = nextRow.createCell(1);
modelNumber.setCellValue(priceListItem.modelNumber);
applyPriceListDataCellStyle(priceListItem, modelNumber);
Cell price = nextRow.createCell(2);
price.setCellValue(priceListItem.price.doubleValue());
applyPriceListDataCellStyle(priceListItem, price);
rowNum++;
}
// resize the columns appropriately
for (int c = 0; c < 3; c++) {
sheet.autoSizeColumn(c);
}
// export to file system
FileOutputStream fos = new FileOutputStream(targetAbsPath);
workbook.write(fos);
fos.close();
inp.close();
workbook.close();
}
private void applyPriceListDataCellStyle(PriceListItem priceListItem, Cell cell) {
short colorIndex;
switch(priceListItem.changeType) {
case ADDITION:
colorIndex = IndexedColors.YELLOW.getIndex();
break;
case DELETION:
colorIndex = IndexedColors.VIOLET.getIndex();
break;
case PRICE_ADJUSTMENT_INCREASE:
colorIndex = IndexedColors.RED.getIndex();
break;
case PRICE_ADJUSTMENT_DECREASE:
colorIndex = IndexedColors.GREEN.getIndex();
break;
default:
// NO_CHANGE (leave unstyled)
colorIndex = IndexedColors.WHITE.getIndex();
break;
}
Map<String,Object> cellProps = new HashMap<>();
cellProps.put(CellUtil.FILL_FOREGROUND_COLOR, colorIndex);
cellProps.put(CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
CellUtil.setCellStyleProperties(cell, cellProps);
}
}
class PriceListItem {
public String modelNumber;
public BigDecimal price;
public ChangeType changeType;
}
enum ChangeType {
NO_CHANGE,
ADDITION,
DELETION,
PRICE_ADJUSTMENT_INCREASE,
PRICE_ADJUSTMENT_DECREASE
}
Result is acme.xlsx which looks like so:
Using IndexedColors the colors are set in Office Open XML /xl/styles.xml as follows:
...
<fill>
<patternFill patternType="solid">
<fgColor indexed="13"/>
<bgColor indexed="64"/>
</patternFill>
</fill>
...
The indexed colors are not given by RGB but are taken from the default color palette. If you have the suspicion that your spreadsheet calculation application uses a different default color palette than Excel, then you can test this using the following code:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellUtil;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class TestIndexedColors {
public static void main(String[] args) throws Exception {
String templateName = "price-list-template.xlsx";
InputStream inp = TestIndexedColors.class.getClassLoader().getResource(templateName).openStream();
Workbook workbook = WorkbookFactory.create(inp);
Sheet sheet = workbook.getSheetAt(0);
Row row; Cell cell; int r = 11;
Map<String,Object> cellProps;
for (IndexedColors color : IndexedColors.values()) {
row = sheet.createRow(r++);
cell = row.createCell(0); cell.setCellValue(color.getIndex());
cell = row.createCell(1); cell.setCellValue(color.name());
cell = row.createCell(2);
cellProps = new HashMap<>();
cellProps.put(CellUtil.FILL_FOREGROUND_COLOR, color.getIndex());
cellProps.put(CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
CellUtil.setCellStyleProperties(cell, cellProps);
}
FileOutputStream out = new FileOutputStream("acme.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
It needs a price-list-template.xlsx having at least one worksheet. The result acme.xlsx shows indexes, names and colors of all possible indexed colors using the current default color palette.
Related
I am using Apache POI to edit an existing file. This file contains multiple formulas that use the numbers that will be inputted through Apache. And this is where I run into problems, when a number is inputted and that cell is being used in a formula, the file gets corrupted and the formula disappears.
Here the formulas for the 0 are C7+D7, C8+D8, etc.
Here the formulas for the 0 became normal 0, the formulas got lost.
Here is the code I used to write to the excel file:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
public class write {
public static void main(String[] args) {
String excelFilePath = "C:\\Users\\jose_\\IdeaProjects\\writeExcel\\src\\JavaBooks.xlsx";
try {
FileInputStream inputStream = new FileInputStream(new File(excelFilePath));
Workbook workbook = WorkbookFactory.create(inputStream);
Sheet sheet = workbook.getSheetAt(0);
/*Cell cell2Update = sheet.getRow(1).getCell(3); // This updates a specific cell: row 0 cell 3
cell2Update.setCellValue(49);*/
Object[][] bookData = {
{2, 17},
{3, 27},
{4, 33},
{5, 44},
};
// int rowCount = sheet.getLastRowNum(); // Gets the last entry
int rowCount = 5;
for (Object[] aBook : bookData) {
Row row = sheet.createRow(++rowCount);
int columnCount = 1;
int lote = 1;
Cell cell = row.createCell(columnCount);
//cell.setCellValue(rowCount); // This sets the index for each entry
cell.setCellValue(lote);
for (Object field : aBook) {
cell = row.createCell(++columnCount);
if (field instanceof String) {
cell.setCellValue((String) field);
} else if (field instanceof Integer) {
cell.setCellValue((Integer) field);
}
}
}
inputStream.close();
FileOutputStream outputStream = new FileOutputStream("C:\\Users\\jose_\\IdeaProjects\\writeExcel\\src\\JavaBooks.xlsx");
workbook.write(outputStream);
workbook.close();
outputStream.close();
} catch (IOException | EncryptedDocumentException ex) {
ex.printStackTrace();
}
}
}
Is there a way to work around this or do I need to set all the formulas again through Apache POI?
You get the error because using code line Row row = sheet.createRow(++rowCount); you always create new empty rows and so you remove all cells in those rows. So you are also removing the cells containing the formulas. Doing so you are damaging the calculation chain. That's what the Excel GUI tells you with the messages.
You should not do this. Instead you always should try to get the rows first using Sheet.getRow. Only if that returns null then you need to create the row.
...
//Row row = sheet.createRow(++rowCount);
Row row = sheet.getRow(rowCount); if (row == null) row = sheet.createRow(rowCount); rowCount++;
...
Additional please read Recalculation of Formulas. So after changing cells referenced in formulas, do always either workbook.getCreationHelper().createFormulaEvaluator().evaluateAll(); or delegate re-calculation to Excel using workbook.setForceFormulaRecalculation(true);.
I'm trying to copy from cells from one workbook to another with the latest version of Apache POI (4.1.2).
If both workbooks are .xlsx files, everything works fine. But if the source workbook is an (old) .xls file and the destination workbook is an .xlsx file, the following code fails
// Copy style from old cell and apply to new cell
CellStyle newCellStyle = targetWorkbook.createCellStyle();
newCellStyle.cloneStyleFrom(sourceCell.getCellStyle());
targetCell.setCellStyle(newCellStyle);
The exception that's thrown is:
java.lang.IllegalArgumentException: Can only clone from one XSSFCellStyle to another, not between HSSFCellStyle and XSSFCellStyle
If we can't use cloneStyleFrom when the files (or Workbook objects) are of different types, how can we convert a HSSFCellStyle object to a XSSFCellStyle?
The answer to your question "How can we convert a HSSFCellStyle object to a XSSFCellStyle?" is: We can't do that using apache poi 4.1.2. This simply is not supported as clearly stated in CellStyle.cloneStyleFrom: "However, both of the CellStyles will need to be of the same type (HSSFCellStyle or XSSFCellStyle)."
The other question is: Should we at all convert one cell style into another? Or what use cases are there for CellStyle.cloneStyleFrom at all? In my opinion there are none. There are Excel limitations for the count of unique cell formats/cell styles. See Excel specifications and limits. So we should not create a single cell style for each single cell because then those limitations will be reached very fast. So instead of cloning cell styles we should get the style properties from source style style1 and then using CellUtil.setCellStyleProperties to set those style properties to the other cell in question. This method attempts to find an existing CellStyle that matches the cell's current style plus styles properties in properties. A new style only is created if the workbook does not contain a matching style.
Since your question title is "Copy cells between Excel workbooks with Apache POI", I have created a working draft of how I woud do this.
The following code first gets a existent Workbook.xls as HSSFWorkbook wb1 and creates a new XSSFWorkbook wb2. Then it loops over all cells of the first sheet of wb1 and tries copying those cells into the first sheet of wb2. To do so there is a method copyCells(Cell cell1, Cell cell2) which uses copyStyles(Cell cell1, Cell cell2). The latter gets the style properties from source style style1 got from cell1 and then uses CellUtil.setCellStyleProperties to set those style properties to cell2. For copying fonts copyFont(Font font1, Workbook wb2) is used. This tries creating new fonts in wb2 only if such a font is not already present in that workbook. This is necessary because there also is a limit of unique font types per workbook in Excel.
Working example:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.util.CellUtil;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.*;
class ExcelCopyCells {
static Font copyFont(Font font1, Workbook wb2) {
boolean isBold = font1.getBold();
short color = font1.getColor();
short fontHeight = font1.getFontHeight();
String fontName = font1.getFontName();
boolean isItalic = font1.getItalic();
boolean isStrikeout = font1.getStrikeout();
short typeOffset = font1.getTypeOffset();
byte underline = font1.getUnderline();
Font font2 = wb2.findFont(isBold, color, fontHeight, fontName, isItalic, isStrikeout, typeOffset, underline);
if (font2 == null) {
font2 = wb2.createFont();
font2.setBold(isBold);
font2.setColor(color);
font2.setFontHeight(fontHeight);
font2.setFontName(fontName);
font2.setItalic(isItalic);
font2.setStrikeout(isStrikeout);
font2.setTypeOffset(typeOffset);
font2.setUnderline(underline);
}
return font2;
}
static void copyStyles(Cell cell1, Cell cell2) {
CellStyle style1 = cell1.getCellStyle();
Map<String, Object> properties = new HashMap<String, Object>();
//CellUtil.DATA_FORMAT
short dataFormat1 = style1.getDataFormat();
if (BuiltinFormats.getBuiltinFormat(dataFormat1) == null) {
String formatString1 = style1.getDataFormatString();
DataFormat format2 = cell2.getSheet().getWorkbook().createDataFormat();
dataFormat1 = format2.getFormat(formatString1);
}
properties.put(CellUtil.DATA_FORMAT, dataFormat1);
//CellUtil.FILL_PATTERN
//CellUtil.FILL_FOREGROUND_COLOR
FillPatternType fillPattern = style1.getFillPattern();
short fillForegroundColor = style1.getFillForegroundColor(); //gets only indexed colors, no custom HSSF or XSSF colors
properties.put(CellUtil.FILL_PATTERN, fillPattern);
properties.put(CellUtil.FILL_FOREGROUND_COLOR, fillForegroundColor);
//CellUtil.FONT
Font font1 = cell1.getSheet().getWorkbook().getFontAt(style1.getFontIndexAsInt());
Font font2 = copyFont(font1, cell2.getSheet().getWorkbook());
properties.put(CellUtil.FONT, font2.getIndexAsInt());
//BORDERS
BorderStyle borderStyle = null;
short borderColor = -1;
//CellUtil.BORDER_LEFT
//CellUtil.LEFT_BORDER_COLOR
borderStyle = style1.getBorderLeft();
properties.put(CellUtil.BORDER_LEFT, borderStyle);
borderColor = style1.getLeftBorderColor();
properties.put(CellUtil.LEFT_BORDER_COLOR, borderColor);
//CellUtil.BORDER_RIGHT
//CellUtil.RIGHT_BORDER_COLOR
borderStyle = style1.getBorderRight();
properties.put(CellUtil.BORDER_RIGHT, borderStyle);
borderColor = style1.getRightBorderColor();
properties.put(CellUtil.RIGHT_BORDER_COLOR, borderColor);
//CellUtil.BORDER_TOP
//CellUtil.TOP_BORDER_COLOR
borderStyle = style1.getBorderTop();
properties.put(CellUtil.BORDER_TOP, borderStyle);
borderColor = style1.getTopBorderColor();
properties.put(CellUtil.TOP_BORDER_COLOR, borderColor);
//CellUtil.BORDER_BOTTOM
//CellUtil.BOTTOM_BORDER_COLOR
borderStyle = style1.getBorderBottom();
properties.put(CellUtil.BORDER_BOTTOM, borderStyle);
borderColor = style1.getBottomBorderColor();
properties.put(CellUtil.BOTTOM_BORDER_COLOR, borderColor);
CellUtil.setCellStyleProperties(cell2, properties);
}
static void copyCells(Cell cell1, Cell cell2) {
switch (cell1.getCellType()) {
case STRING:
/*
//TODO: copy HSSFRichTextString to XSSFRichTextString
RichTextString rtString1 = cell1.getRichStringCellValue();
cell2.setCellValue(rtString1); // this fails if cell2 is XSSF and rtString1 is HSSF
*/
String string1 = cell1.getStringCellValue();
cell2.setCellValue(string1);
break;
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell1)) {
Date date1 = cell1.getDateCellValue();
cell2.setCellValue(date1);
} else {
double cellValue1 = cell1.getNumericCellValue();
cell2.setCellValue(cellValue1);
}
break;
case FORMULA:
String formula1 = cell1.getCellFormula();
cell2.setCellFormula(formula1);
break;
//case : //TODO: further cell types
}
copyStyles(cell1, cell2);
}
public static void main(String[] args) throws Exception {
Workbook wb1 = WorkbookFactory.create(new FileInputStream("Workbook.xls"));
Workbook wb2 = new XSSFWorkbook();
Sheet sheet1 = wb1.getSheetAt(0);
Sheet sheet2 = wb2.createSheet();
Set<Integer> columns = new HashSet<Integer>();
Row row2 = null;
Cell cell2 = null;
for (Row row1 : sheet1) {
row2 = sheet2.createRow(row1.getRowNum());
for (Cell cell1 : row1) {
columns.add(cell1.getColumnIndex());
cell2 = row2.createCell(cell1.getColumnIndex());
copyCells(cell1, cell2);
}
}
wb1.close();
for (Integer column : columns) {
sheet2.autoSizeColumn(column);
}
FileOutputStream out = new FileOutputStream("Workbook.xlsx");
wb2.write(out);
out.close();
wb2.close();
}
}
If Workbook.xls looks like this:
then the resulting Workbook.xlsx looks like this:
Note: This is a working draft and needs to be completed. See TODO comments in the code. RichTextString cell values needs to be considered. Further cell types needs to be considered.
Method copyStyles only provides copying data format, fill pattern and fill foreground color (only for indexed colors), font and borders. Further cell style properties needs to be considered.
I am using apache poi 3.17 to create an Excel file.
Different columns may contain different type of values and I would like to style them accordingly. Rather than creating the style every time, I try to use the same style( to avoid the unnecessary object creation) and change the necessary properties. For eg: some cell I want to make italics, some bold, some with yellow color, some with underline etc..
But to my surprise, I found that style is not changing.
Below is a sample code where I try to set row 1 with 'yellow color' and rest with 'red color' but in the generated excel all rows are red.
import org.apache.poi.common.usermodel.HyperlinkType;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Hyperlink;
import org.apache.poi.xssf.usermodel.*;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class WriteExcelBasic {
public static void main(String[] args) throws IOException {
String excelFileName = "/Users/username/Test3.xlsx";
FileOutputStream fos = new FileOutputStream(excelFileName);
XSSFWorkbook wb = new XSSFWorkbook();
XSSFCellStyle style = wb.createCellStyle();
XSSFSheet sheet = wb.createSheet("sheet");
Font urlFont = wb.createFont();
urlFont.setFontHeight((short)(9*20));
style.setFont(urlFont);
for (int r = 0; r < 3; r++) {
XSSFRow row = sheet.createRow(r);
for (int c = 0; c < 3; c++) {
XSSFCell cell = row.createCell(c);
Hyperlink link = wb.getCreationHelper().createHyperlink(HyperlinkType.URL);
String ss = "http://news.google.com/news/headlines?ned=us&hl=en";
link.setAddress(ss);
cell.setHyperlink(link);
cell.setCellValue(ss);
if(r == 1) {
System.out.println("In yellow");
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(new XSSFColor(Color.YELLOW));
} else {
System.out.println("In red");
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(new XSSFColor(Color.RED));
}
cell.setCellStyle(style);
}
}
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
wb.write(baos);
byte[] myByteArray = baos.toByteArray();
fos.write(myByteArray);
fos.flush();
}
finally {
wb.close();
fos.close();
}
}
}
To solve this issue, I could create 2 styles separately and apply them based on the condition but in a practical case I have to create 24 different styles but for that, I have to write so much redundant code.
If I want to create a new style with a different property then I have to create another 24 styles with this new property. Therefore the complexity will go exponentially.
Therefore, can anyone provide some suggestion on this issue?
I am using Java 8, excel and apache poi for my project. There are certain cell values that I am interested in extracting from excel using java. I am trying to detect text which is strikeout in the excel cells, but the format of text is little different that is why I am facing some problems.
Below is how data laid out in my excel sheet:
After extacting this data from excel, I always save it in string arraylist format like this a = [text 1, text 2, text 3]. code is mentioned below if you want to see how I am storing data in this arraylist.
What I want:
I want to ignore all those texts which are strikeout, so in above case I expect to have output like this [text 2, text 3] for first picture and second picture.
What I tried:
For the sake of just detecting strikeout values, I tried below code first:
XSSFRichTextString text = new XSSFRichTextString(a.get(0));
XSSFFont font = text.getFontAtIndex(0);
Boolean font_striked = font.getStrikeout();
but above code is not working as font_striked returns null, it must return true or false
The code which partially works in my case on single line cell values is:
boolean striked_out = sheet.getRow(row_index).getCell(column_index).getCellStyle().
getFont().getStrikeout();
This code only works if there is single line value in the cell and not with bullet list as shown above. It fails as it is not made for such kind of text.
P.S
I believe that if somehow I am able to detect even a single strikeout string in bullet points from arraylist, I can make it work for all the data.
As per the answer below I have updated my question adding following code to show how I make my string arraylist
How I convert data in excel into Arraylist:
String value_header = cell.getStringCellValue();
String[] newline_split = value_header.split("-");
for (int i = 0; i < newline_split.length; i++){
final_values = newline_split[i].
replace("\n"," ").replaceAll("\\s{2,}", " ").trim();
XSSFRichTextString text = new XSSFRichTextString(final_values);
XSSFFont font = text.getFontAtIndex(0);
Boolean font_striked = font.getStrikeout();
} // for ends here
You will need to get the RichTextString first, then go through all FormattingRuns, check whether it is stroked out and only if not, then get the appropriated substring and put it into the List:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.CellType.*;
import org.apache.poi.xssf.usermodel.*;
import java.io.FileInputStream;
import java.util.List;
import java.util.ArrayList;
class ReadExcelRichTextCells {
public static void main(String[] args) throws Exception {
Workbook wb = WorkbookFactory.create(new FileInputStream("ExcelRichTextCells.xlsx"));
Sheet sheet = wb.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
switch (cell.getCellTypeEnum()) {
case STRING:
XSSFRichTextString richtextstring = (XSSFRichTextString)cell.getRichStringCellValue();
String textstring = richtextstring.getString();
List<String> textparts = new ArrayList<String>();
if (richtextstring.hasFormatting()) {
for (int i = 0; i < richtextstring.numFormattingRuns(); i++) {
if (richtextstring.getFontOfFormattingRun(i)==null || !richtextstring.getFontOfFormattingRun(i).getStrikeout()) {
int indexofformattingrun = richtextstring.getIndexOfFormattingRun(i);
String textpart = textstring.substring(indexofformattingrun,
indexofformattingrun + richtextstring.getLengthOfFormattingRun(i));
String[] textpart_split = textpart.split("-");
for (int j = 0; j < textpart_split.length; j++){
String text = textpart_split[j].replace("\n", "").trim();
if (!"".equals(text)) textparts.add(text);
}
}
}
} else {
textparts.add(textstring);
}
System.out.println(textparts);
break;
//...
default:
System.out.println("default cell"); //should never occur
}
}
}
wb.close();
}
}
This is how to get the strikethrough in Excel with VBA:
Public Sub IsMyActivecellStriked()
Debug.Print ActiveCell.Font.Strikethrough
End Sub
If you have something like this:
Then the you should find a way to access the characters and check for them. Like this:
Option Explicit
Public Sub TestMe()
Dim strRange As String
Dim varArr As Variant
Dim varStr As Variant
Dim lngStart As Long
Dim lngEnd As Long
strRange = [a1]
varArr = Split(strRange, Chr(10))
For Each varStr In varArr
lngStart = InStr(1, strRange, varStr)
Debug.Print [a1].Characters(Start:=lngStart, Length:=Len(varStr)).Font.Strikethrough
Debug.Print [a1].Characters(Start:=lngStart, Length:=Len(varStr)).Text
Next varStr
End Sub
This will give you the following in the immediate window:
False
aaa
True
bbb
True
ccc
False
ddd
This should be possible to be translated into Java with the POI library.
As per I understanding above question Question (plz Correct me if I am wrong..!)
It should show whether your text in cell is strikethrough or not. ( TRUE or FALSE)
Below I have created a demo with that :
public class ApachePOI {
public static void main(String[] args) {
//Using workbook
XSSFWorkbook workbook;
try {
//Access excel file as workbook
workbook = new XSSFWorkbook(new FileInputStream(new File("/testExcelfile.xlsx")));
// first sheet of excel file
XSSFSheet xssfFirstSheet = workbook.getSheetAt(0);
//Check for A1 cell that strikethrough or not
boolean strikedOutTextStatus = xssfFirstSheet.getRow(0).getCell(0).getCellStyle().getFont().getStrikeout();
//print status of A1 cell text
System.out.println(strikedOutTextStatus);
// UPDATED CODE
if(strikedOutTextStatus){
String cellStringValue = xssfFirstSheet.getRow(0).getCell(0).getStringCellValue();
System.out.println("cell Value : "+cellStringValue.replace("-", "").replace(" ", ""));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I use the code that you can see below in order to strike through some cells in a jtable. Works great for me, and both in appearence and in print with JTable.print() method works excellent.
public void strikeThrough()
{
int rows=jTable.getRowCount();
destroiedDocs=new ArrayList<>();
for (int i = 0; i < rows; i++)
{
String test=String.valueOf(jTable.getValueAt(i,5));
if (test.equals("K"))
{
for (int j = 1; j < 5; j++)
{
String tostrike= String.valueOf(jTable.getValueAt(i, j));
String striked=("<html><strike>".concat(tostrike).concat("</strike> </html>"));
jTable.setValueAt(striked, i, j);
destroiedDocs.add(i);
}
}
}
}
The problem is that when I export the resaults to excel with the jxl class I got the value in these strike through cells with the appearence
<html><strike>some text</strike></html>
instead of some text in strikethrough.
Any recomandations on how to solve this formating problem?
I pass the cells in the excel cell by cell from the jtable with loops.
Thank you!
The JAVA code:
String striked=("<html><strike>".concat(tostrike).concat("</strike> </html>"));
jTable.setValueAt(striked, i, j);
Will work only for JAVA UI. After exporting data to excel it will show original text.
You need to perform following steps:
1. Before exporting remove <html><strike> and </strike></html>. Keep original text.
2. Use following code to strikethrough cell.
Run the following code using jxl-2.6.10.jar
import java.io.File;
import jxl.Workbook;
import jxl.write.Label;
import jxl.write.WritableCell;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
public class ExcelCreate {
public static void main(String[] args) {
try {
WritableWorkbook workbook =
Workbook.createWorkbook(new File("output.xls"));
WritableSheet sheet = workbook.createSheet("Page1", 0);
String Label[] = new String[4];
Label[0] = "Emp ID";
Label[1] = "Name";
Label[2] = "Department";
Label[3] = "Designation";
WritableCellFormat cellFormat = new WritableCellFormat();
WritableFont font = new WritableFont(WritableFont.ARIAL);
font.setStruckout(true);
cellFormat.setFont(font);
for (int i = 0; i < Label.length; i++) {
Label label = new Label(i, 0, Label[i]);
sheet.addCell(label);
WritableCell cell = sheet.getWritableCell(i, 0);
cell.setCellFormat(cellFormat);
}
workbook.write();
workbook.close();
} catch (Exception e) {
/* Write your logic to handle exception.
*/
}
}
}
I think before export each cell to the Excel you'll have to find and replace or remove the tags like
<html>
and
<strike>
with appropriate functions to add the required formatting..
Which API are you using to export it to Excel Format??
I think it'll be Specific the one that you're using to export to Excel.