Apache POI 不应用某些颜色索引

Apache POI not applying certain color indices

Java 8 和 Apache POI 4.1.x 在这里。我有一些 Java 代码可以将对象列表写入 Excel 文件并且它的工作 完美 很好,除了一些基于颜色的单元格样式我我正在尝试申请:

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

}

上面,applyPriceListDataCellStyle 方法在Row 对象创建 Cell 之后被调用。然后将 cell 实例作为参数传递给此方法,连同我的 PriceListItem bean(这是我写入 Excel 文件中每一行的数据)。

PriceListItem bean 有一个 ChangeType 属性(枚举),它规定单元格在最终 Excel 文件中应显示的颜色。

在运行时,我在每个 ChangeType 值的 5 个不同行(因此 5 个不同 PriceListItems)的单元格上调用此方法,我得到的输出如下所示:

所以:

我在哪里设置这些不同行的单元格的颜色?

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。因此是黑色,因为在你的代码中 purple.getIndex() 总是 returns 0。因此,如果要使用 CellUtil,这是推荐的,则从 IndexedColors 中选择一种颜色,而不是创建自定义颜色。例如有IndexedColors.VIOLET

但是其他错误的情况对我来说是不可重现的。以下 Minimal, Reproducible Example 按预期对我有效。它需要一个 price-list-template.xlsx 至少有一个工作表。

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
}

结果是 acme.xlsx,看起来像这样:


使用 IndexedColorsOffice Open XML /xl/styles.xml 中设置颜色如下:

...
<fill>
 <patternFill patternType="solid">
  <fgColor indexed="13"/>
  <bgColor indexed="64"/>
 </patternFill>
</fill>
...

索引颜色不是由 RGB 给出的,而是取自默认调色板。如果您怀疑您的电子表格计算应用程序使用与 Excel 不同的默认调色板,那么您可以使用以下代码进行测试:

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

它需要一个 price-list-template.xlsx 至少有一个工作表。结果 acme.xlsx 使用当前默认调色板显示所有可能的索引颜色的索引、名称和颜色。