copy cells between Excel workbooks with Apache POI - java

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.

Related

POI CellStyle does not appear to be applied

Please note: I see a very similar question asked here but that answer was not very conclusive (I can't discern what the actual fix is/was). If someone can explain to me how that question/answer addresses my present issue at hand, I will happily delete this question myself! Just please don't DV/CV as a "dupe", and instead please help me make sense of that provided solution!
Java 8 and POI 4.1.x here. I am trying to write some Java/POI code that will produce a styled/formatted Excel file as output. I have created this GitHub project that perfectly reproduces the issue I'm seeing. If you really want, you can take a look at it and run it (its a Swing app) via ./gradlew clean build shadowJar && java -jar build/libs/hello-windows.jar, but the TLDR; of it is:
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("SOME_SHEET");
Font headerFont = workbook.createFont();
headerFont.setBold(true);
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setFont(headerFont);
cellStyle.setFillBackgroundColor(IndexedColors.YELLOW.getIndex());
cellStyle.setAlignment(HorizontalAlignment.CENTER);
int rowNum = 0;
Row headerRow = sheet.createRow(rowNum);
headerRow.setRowStyle(cellStyle);
Cell partNumberHeaderCell = headerRow.createCell(0);
partNumberHeaderCell.setCellValue("Part #");
partNumberHeaderCell.setCellStyle(cellStyle);
Cell partDescriptionHeaderCell = headerRow.createCell(1);
partDescriptionHeaderCell.setCellStyle(cellStyle);
partDescriptionHeaderCell.setCellValue("Description");
Cell partPriceHeaderCell = headerRow.createCell(2);
partPriceHeaderCell.setCellStyle(cellStyle);
partPriceHeaderCell.setCellValue("Price");
Cell manufacturerHeaderCell = headerRow.createCell(3);
manufacturerHeaderCell.setCellStyle(cellStyle);
manufacturerHeaderCell.setCellValue("Make");
rowNum++;
Row nextRow = sheet.createRow(rowNum);
nextRow.createCell(0).setCellValue(uuid);
nextRow.createCell(1).setCellValue("Some Part");
nextRow.createCell(2).setCellValue(2.99);
nextRow.createCell(3).setCellValue("ACME");
FileOutputStream fos = null;
try {
fos = new FileOutputStream("acme.xlsx");
workbook.write(fos);
workbook.close();
} catch (IOException ex) {
log.error(ExceptionUtils.getStackTrace(ex));
}
When this code runs it produces an Excel file that contains all my data (the header row and a "data" row) correctly, however all the formatting and cell styling seems to be ignored:
In the screenshot above, you can see that the header is not styled at all, however I believe I am styling it correctly:
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setFont(headerFont);
cellStyle.setFillBackgroundColor(IndexedColors.YELLOW.getIndex());
cellStyle.setAlignment(HorizontalAlignment.CENTER);
If my code is correct then I should see a header that:
Has a yellow background; and
Is horizontally-centered/aligned; and
Is bolded
Can anyone spot where I'm going awry?
Not clear why the bold font not gets applied for you, for me it gets.
But the problem with the cell interior is that Excel cell interiors have pattern fills. There the fill background color is the color behind the pattern and the fill foreground color is the color of the pattern. Solid filled cell interiors must have solid pattern having the needed fill foreground color set.
See also Busy Developers' Guide to HSSF and XSSF Features.
...
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setFont(headerFont);
//cellStyle.setFillBackgroundColor(IndexedColors.YELLOW.getIndex());
cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setAlignment(HorizontalAlignment.CENTER);
...
Let's have a complete example which will store your data in an Excel sheet:
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
class CreateExcelCellStyle {
public static void main(String[] args) throws Exception {
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("./Excel.xlsx") ) {
Font headerFont = workbook.createFont();
headerFont.setBold(true);
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headerStyle.setAlignment(HorizontalAlignment.CENTER);
Object[][] data = new Object[][] {
new Object[] {"Part #", "Description", "Price", "Make"},
new Object[] {"cb82c02", "Some Part", 2.99, "ACME"}
};
Sheet sheet = workbook.createSheet();
for (int r = 0; r < data.length; r++) {
Row row = sheet.createRow(r);
for (int c = 0; c < data[0].length; c++) {
Cell cell = row.createCell(c);
if (r==0) cell.setCellStyle(headerStyle);
Object content = data[r][c];
if (content instanceof String) {
cell.setCellValue((String)content);
} else if (content instanceof Double) {
cell.setCellValue((Double)content);
}
}
}
for (int c = 0; c < data[0].length; c++) {
sheet.autoSizeColumn(c);
}
workbook.write(fileout);
}
}
}
Result:

POI and setting cells to VerticalAlignment.MIDDLE

Hey all I am trying to get my cell to vertical line instead of just being aligned by the left side using POI.
This is my java code:
static CellStyle headerCellStyle = workbook.createCellStyle();
headerCellStyle = workbook.createCellStyle();
Row headerRow = null;
sheet = workbook.createSheet("String " + sheetname);
headerCellStyle.setWrapText(true);
headerCellStyle.setAlignment(HorizontalAlignment.LEFT);
headerCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headerCellStyle.setVerticalAlignment(VerticalAlignment.MIDDLE);
// Create a Row
headerRow = sheet.createRow(0);
However, the line headerCellStyle.setVerticalAlignment(VerticalAlignment.MIDDLE); has an error of:
The method setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment) in the type CellStyle is not applicable for the arguments (org.apache.poi.sl.usermodel.VerticalAlignment)
How can i go about getting this to work if I have already defined it as an static CellStyle headerCellStyle = workbook.createCellStyle();?
Changing to SS does not seem to have the "middle" option?
This is the difference within excel for those 2 types:
The default way:
The Middle way (the way I am wanting):
The Center way:
Your second image (the way you want) shows CellStyle.setVerticalAlignment(VerticalAlignment.CENTER). Your third image shows CellStyle.setAlignment(HorizontalAlignment.CENTER).
There is a difference between setVerticalAlignment(VerticalAlignment.CENTER) and setAlignment(HorizontalAlignment.CENTER). The first sets vertical alignment to center (aka middle). The second sets horizontal alignment to center.
Complete Example:
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
class CreateExcelVerticalAlignment {
public static void main(String[] args) throws Exception {
// try (Workbook workbook = new XSSFWorkbook();
// FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {
try (Workbook workbook = new HSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("Excel.xls") ) {
CellStyle headerCellStyle = workbook.createCellStyle();
headerCellStyle = workbook.createCellStyle();
headerCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
Sheet sheet = workbook.createSheet();
sheet.setColumnWidth(0, 20*256);
Row row = sheet.createRow(0);
row.setHeightInPoints(40);
Cell cell = row.createCell(0);
cell.setCellStyle(headerCellStyle);
cell.setCellValue("1082192560 1868");
workbook.write(fileout);
}
}
}
Result:

String cells data is not visible in excel editor when excel is created using SXSSFWorkbook and modified using XSSFWorkbook

Scenario:
1) A csv file is converted into excel file using SXSSFWorkbook.
2) If the data is again read from CSV file and written to the above generated excel file using XSSFWorkbook then the string data is not visible in libre office but data is visible if the excel file is opened in online excel viewer(some of the excel viewers are mentioning that the file is corrupt and data can be recoverable).
Cell creation Using SXSSFWorkbook:
Cell cell = row.createCell(1);
cell.setCellValue("Some Value");
Cell updation using XSSFWorkbook:
Cell cell = row.getCell(1);
cell.setCellValue("Some Value");
Observations:
1) When cell value is updated using XSSFCell, then the raw value of cell and string value of the cell are different.
2) If excel file is generated with SXSSFWorkbook and opened using XSSFWorkbook then internally maintained STCellType is STCellType.INLINE_STR and if excel file is generated using XSSFWorkbook then internally maintained STCellType is STCellType.S (STCellType is used in CTCell of XSSFCell).
Apache POI Version: 4.1.0
Please suggest solution.
The SXSSFWorkbook uses inline strings per default while XSSFWorkbook uses shared strings table per default. And XSSFCell.setCellValueImpl is incomplete for inline strings. It does:
...
if(_cell.getT() == STCellType.INLINE_STR) {
//set the 'pre-evaluated result
_cell.setV(str.getString());
}
...
So for inline strings it always sets v element containing the text. But inline strings also may have is element having t element containing the text, or even is element having different rich text runs. This is not considered using XSSFCell.
But SXSSFWorkbook can be constructed so it also uses shared strings table. See constructor SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles, boolean useSharedStringsTable). So if following constructor used:
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(), 2, true, true);
then no inline strings are used and later updating using XSSF will not be problematic.
If SXSSFWorkbook is not using shared strings table but inline strings, there is a problem when later updating cells using XSSF because of the incompleteness of XSSFCell in using inline strings. Possible workaround will be managing the inline strings updating with own code.
Example:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.xssf.streaming.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;
public class SXSSFTest {
public static void main(String[] args) throws Exception {
// first create SXSSFTest.xlsx using SXSSF ============================================
String[][] data1 = new String[][]{
new String[]{"A1", "B1", "C1"},
new String[]{"A2", "B2", "C2"},
new String[]{"A3", "B3", "C3"},
new String[]{"A4", "B4", "C4"}
};
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook();
//SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(), 2, true, true);
SXSSFSheet sxssfSheet = sxssfWorkbook.createSheet();
int r = 0;
for (String[] rowValues : data1) {
SXSSFRow row = sxssfSheet.createRow(r++);
int c = 0;
for (String value : rowValues) {
SXSSFCell cell = row.createCell(c++);
cell.setCellValue(value);
}
}
FileOutputStream outputStream = new FileOutputStream("SXSSFTest.xlsx");
sxssfWorkbook.write(outputStream);
outputStream.close();
sxssfWorkbook.dispose();
sxssfWorkbook.close();
// now reread the SXSSFTest.xlsx and update it using XSSF =============================
String[][] data2 = new String[][]{
new String[]{"A2 New", "B2 New", "C2 New"},
new String[]{"A3 New", "B3 New", "C3 New"}
};
XSSFWorkbook xssfWorkbook = (XSSFWorkbook)WorkbookFactory.create(
new FileInputStream("SXSSFTest.xlsx"));
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0);
r = 1;
for (String[] rowValues : data2) {
XSSFRow row = xssfSheet.getRow(r++); if (row == null) row = xssfSheet.createRow(r++);
int c = 0;
for (String value : rowValues) {
XSSFCell cell = row.getCell(c++);
if (cell != null) { // cell was already there
if (cell.getCTCell().getT() == STCellType.INLINE_STR) { // cell has inline string in it
if (cell.getCTCell().isSetIs()) { // inline string has is element
cell.getCTCell().getIs().setT(value); // set t element in is element
} else {
cell.getCTCell().setV(value); // set v element of inline string
}
} else {
cell.setCellValue(value); // set shared string cell value
}
} else {
cell = row.createCell(c++);
cell.setCellValue(value);
}
}
}
outputStream = new FileOutputStream("XSSFTest.xlsx");
xssfWorkbook.write(outputStream);
outputStream.close();
xssfWorkbook.close();
}
}
After that the SXSSFTest.xlsx looks like so in my LibreOffice Calc:
All cells have inline strings in it.
And the XSSFTest.xlsx looks like so:
There all inline strings are updated correctly now.
LibreOffice
Version: 6.0.7.3
Build ID: 1:6.0.7-0ubuntu0.18.04.5

Apache-POI: Cell Background Color doesn't work

I'm trying to configure generic CellStyles for formating HSSFCells using Apache-POI 3.11.
Here is a runnable sample of the code. The bold and border formating is being correctly aplied. The problem is with the Background and Foreground colors.
Any clue of what am I doing wrong?
public class TestSO {
private final static short
MY_LIGHT_BLUE=100,
MY_DARK_BLUE=101,
MY_BLACK=102,
MY_WHITE=103;
public static void main(String[]args) throws Exception{
HSSFWorkbook workbook = new HSSFWorkbook();
setPallete( workbook.getCustomPalette() );
HSSFFont fontNormal = workbook.createFont();
fontNormal.setFontHeightInPoints((short)11);
fontNormal.setFontName("Calibri");
HSSFFont fontBold = workbook.createFont();
fontBold.setFontHeightInPoints((short)11);
fontBold.setFontName("Calibri");
fontBold.setBold(true);
HSSFCellStyle titleStyle = workbook.createCellStyle();
titleStyle.setFillBackgroundColor(MY_DARK_BLUE);
titleStyle.setFillForegroundColor(MY_WHITE);
titleStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
titleStyle.setFont(fontBold);
setTopBotBorder(titleStyle);
HSSFCellStyle fpStyle = workbook.createCellStyle();
fpStyle.setFillBackgroundColor(MY_LIGHT_BLUE);
fpStyle.setFillForegroundColor(MY_BLACK);
fpStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
fpStyle.setFont(fontNormal);
setTopBotBorder(fpStyle);
HSSFSheet sheet = workbook.createSheet("Leyenda");
HSSFCell cell;
cell = sheet.createRow( 1 ).createCell( 1 );
cell.setCellValue("TitleStyle");
cell.setCellStyle(titleStyle);
cell = sheet.createRow( 2 ).createCell( 1 );
cell.setCellValue("FpStyle");
cell.setCellStyle(fpStyle);
sheet.autoSizeColumn(1);
try (FileOutputStream fos = new FileOutputStream( new File("TestWB.xls") )) {
workbook.write( fos );
}
}
private static void setPallete( HSSFPalette pallete ){
pallete.setColorAtIndex(MY_LIGHT_BLUE, (byte)189,(byte)215,(byte)238);
pallete.setColorAtIndex(MY_DARK_BLUE, (byte)32,(byte)55,(byte)100);
pallete.setColorAtIndex(MY_BLACK, (byte)0,(byte)0,(byte)0);
pallete.setColorAtIndex(MY_WHITE, (byte)255,(byte)255,(byte)255);
}
private static void setTopBotBorder( CellStyle style ){
style.setBorderBottom(CellStyle.BORDER_THIN);
style.setBottomBorderColor(MY_BLACK);
style.setBorderTop(CellStyle.BORDER_THIN);
style.setTopBorderColor(MY_BLACK);
}
}
Here is the Excel file output:
Thanks in advance.
I think there are a couple of things you need to change. Firstly you can't just assign new index values for your custom colors. The pallete is already full, and so you need to overwrite existing colors with your own custom ones. Therefore try changing the definition of your two blues to:
private final static short MY_LIGHT_BLUE = HSSFColor.CORNFLOWER_BLUE.index,
MY_DARK_BLUE = HSSFColor.BLUE.index;
Secondly, I never set both the foreground and background colors at the same time as this seems to clash. To change the color in the cell, try just setting the foreground color, for example:
HSSFCellStyle titleStyle = workbook.createCellStyle();
titleStyle.setFillForegroundColor(MY_DARK_BLUE);
titleStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
titleStyle.setFont(fontBold);
setTopBotBorder(titleStyle);
If you then want to change the color of the actual text in the cell, you can change the color of the Font for example:
fontNormal.setColor(HSSFColor.RED.index);
I have tested this out and it seems to work.

Changing cell color using apache poi

I'm using Apache POI to read data in a spreadsheet of part numbers. I look up the part number in our database, if we have a CAD drawing of the part I color the part number cell green, if we don't I color it red. After the processing is done the spreadsheet is saved. The problem I'm having is that every cell in that column comes out green. I've stepped through the code, the logic to look up the part number is working fine and the logic to determine what color the cell should be and setting the color and fill appears to work as well. Any ideas what I'm doing wrong here?
Thanks.
//Check the parts
for(int r=1;r<sheet.getPhysicalNumberOfRows();r++) {
String partNumber = null;
switch(cell.getCellType()) {
case HSSFCell.CELL_TYPE_NUMERIC:
long pNum = (long) cell.getNumericCellValue();
partNumber = String.valueOf(pNum);
break;
case HSSFCell.CELL_TYPE_STRING:
partNumber = cell.getStringCellValue();
break;
default:
logger.info("Part Number at row " + r + " on sheet " + partList.getSheetName(s) + "is of an unsupported type");
}
try {
List<String> oldMaterialNumbers = getOldMaterialNumbers(partNumber);
boolean gotDrawing = checkPartNumber(oldMaterialNumbers, partNumber);
//If there's a drawing then color the row green, if not red.
short bgColorIndex = gotDrawing
?HSSFColor.LIGHT_GREEN.index //42
:HSSFColor.RED.index; //10
HSSFCell curCell = row.getCell(partNumberColumn);
HSSFCellStyle curStyle = curCell.getCellStyle();
curStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
curStyle.setFillForegroundColor(bgColorIndex);
curCell.setCellStyle(curStyle);
}catch(Exception e) {
throw e;
}
}
Short version: Create styles only once, use them everywhere.
Long version: use a method to create the styles you need (beware of the limit on the amount of styles).
private static Map<String, CellStyle> styles;
private static Map<String, CellStyle> createStyles(Workbook wb){
Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
DataFormat df = wb.createDataFormat();
CellStyle style;
Font headerFont = wb.createFont();
headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
headerFont.setFontHeightInPoints((short) 12);
style = createBorderedStyle(wb);
style.setAlignment(CellStyle.ALIGN_CENTER);
style.setFont(headerFont);
styles.put("style1", style);
style = createBorderedStyle(wb);
style.setAlignment(CellStyle.ALIGN_CENTER);
style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
style.setFillPattern(CellStyle.SOLID_FOREGROUND);
style.setFont(headerFont);
style.setDataFormat(df.getFormat("d-mmm"));
styles.put("date_style", style);
...
return styles;
}
you can also use methods to do repetitive tasks while creating styles hashmap
private static CellStyle createBorderedStyle(Workbook wb) {
CellStyle style = wb.createCellStyle();
style.setBorderRight(CellStyle.BORDER_THIN);
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderBottom(CellStyle.BORDER_THIN);
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderLeft(CellStyle.BORDER_THIN);
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderTop(CellStyle.BORDER_THIN);
style.setTopBorderColor(IndexedColors.BLACK.getIndex());
return style;
}
then, in your "main" code, set the style from the styles map you have.
Cell cell = xssfCurrentRow.createCell( intCellPosition );
cell.setCellValue( blah );
cell.setCellStyle( (CellStyle) styles.get("style1") );
To create your cell styles see: http://poi.apache.org/spreadsheet/quick-guide.html#CustomColors.
Custom colors
HSSF:
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
HSSFRow row = sheet.createRow((short) 0);
HSSFCell cell = row.createCell((short) 0);
cell.setCellValue("Default Palette");
//apply some colors from the standard palette,
// as in the previous examples.
//we'll use red text on a lime background
HSSFCellStyle style = wb.createCellStyle();
style.setFillForegroundColor(HSSFColor.LIME.index);
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
HSSFFont font = wb.createFont();
font.setColor(HSSFColor.RED.index);
style.setFont(font);
cell.setCellStyle(style);
//save with the default palette
FileOutputStream out = new FileOutputStream("default_palette.xls");
wb.write(out);
out.close();
//now, let's replace RED and LIME in the palette
// with a more attractive combination
// (lovingly borrowed from freebsd.org)
cell.setCellValue("Modified Palette");
//creating a custom palette for the workbook
HSSFPalette palette = wb.getCustomPalette();
//replacing the standard red with freebsd.org red
palette.setColorAtIndex(HSSFColor.RED.index,
(byte) 153, //RGB red (0-255)
(byte) 0, //RGB green
(byte) 0 //RGB blue
);
//replacing lime with freebsd.org gold
palette.setColorAtIndex(HSSFColor.LIME.index, (byte) 255, (byte) 204, (byte) 102);
//save with the modified palette
// note that wherever we have previously used RED or LIME, the
// new colors magically appear
out = new FileOutputStream("modified_palette.xls");
wb.write(out);
out.close();
XSSF:
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet();
XSSFRow row = sheet.createRow(0);
XSSFCell cell = row.createCell( 0);
cell.setCellValue("custom XSSF colors");
XSSFCellStyle style1 = wb.createCellStyle();
style1.setFillForegroundColor(new XSSFColor(new java.awt.Color(128, 0, 128)));
style1.setFillPattern(CellStyle.SOLID_FOREGROUND);
I believe it is because cell.getCellStyle initially returns the default cell style which you then change.
Create styles like this and apply them to cells:
cellStyle = (XSSFCellStyle) cell.getSheet().getWorkbook().createCellStyle();
Although as the previous poster noted try and create styles and reuse them.
There is also some utility class in the XSSF library that will avoid the code I have provided and automatically try and reuse styles. Can't remember the class 0ff hand.
checkout the example here
http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/ss/examples/BusinessPlan.java
style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
For apache POI 3.9 you can use the code bellow:
HSSFCellStyle style = workbook.createCellStyle()
style.setFillForegroundColor(HSSFColor.YELLOW.index)
style.setFillPattern((short) FillPatternType.SOLID_FOREGROUND.ordinal())
The methods for 3.9 version accept short and you should pay attention to the inputs.

Categories

Resources