Apache POI 3.9 conditional formatting (string value) - apache-poi

I have the following code set up in my servlet to format a column based
on a string value but, I get an error when trying to compile (org.apache.poi.ss.formula.FormulaParseException: Specified named range 'green' does not exist in the current workbook.). How should I test for a string value?
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
// Condition 1: Cell Value is equal to green (Green Fill)
ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(ComparisonOperator.EQUAL, "green");
PatternFormatting fill1 = rule1.createPatternFormatting();
fill1.setFillBackgroundColor(IndexedColors.GREEN.index);
fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
// Condition 2: Cell Value Is equal to yellow (Yellow Fill)
ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(ComparisonOperator.EQUAL, "yellow");
PatternFormatting fill2 = rule2.createPatternFormatting();
fill2.setFillBackgroundColor(IndexedColors.YELLOW.index);
fill2.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
CellRangeAddress[] regions = {
CellRangeAddress.valueOf("B1:B44")
};
sheetCF.addConditionalFormatting(regions, rule1, rule2);

I had this problem and solved it by adding double quotes on the strings so that "green" becomes "\"green\"".
ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"green\"");
Hope it works.

Use updated one... Its working when you apply both the rules individually
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
// Condition 1: Cell Value is equal to green (Green Fill)
ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(ComparisonOperator.EQUAL, "green");
PatternFormatting fill1 = rule1.createPatternFormatting();
fill1.setFillBackgroundColor(IndexedColors.GREEN.index);
fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
CellRangeAddress[] regions = {CellRangeAddress.valueOf("B1:B44")};
sheetCF.addConditionalFormatting(regions, rule1);
// Condition 2: Cell Value Is equal to yellow (Yellow Fill)
ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(ComparisonOperator.EQUAL, "yellow");
PatternFormatting fill2 = rule2.createPatternFormatting();
fill2.setFillBackgroundColor(IndexedColors.YELLOW.index);
fill2.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
sheetCF.addConditionalFormatting(regions, rule2);

Related

XSSFWorkbook make part of cell content to bold using apache poi

My project need is to make part of a string bold leaving any OR and AND like the below example.
TOWING PACK 11 OR TOWING PACK 13 AND TOWING PACK 14 OR TOWING PACK 15
I tried to follow the reverse approach.
I tried to make the entire cell BOLD // This works
Then using RichTextString make "OR" and "AND" to normal Italics. //The issue - After the first "OR" all the rest of the string is formatted to normal format.
Output I am getting:
TOWING PACK 11 OR TOWING PACK 13 AND TOWING PACK 14 OR TOWING PACK 15
I am using poi 5.2.3 and below is the code sample. Can anyone point out what is wrong here.
CreationHelper creationHelper = workbook.getCreationHelper();
XSSFFont fontBold = workbook.createFont();
fontBold.setBold(true);
XSSFFont fontItalic = workbook.createFont();
fontItalic.setItalic(true);
fontItalic.setBold(false);
XSSFCellStyle boldstyle = workbook.createCellStyle();
boldstyle.setFont(fontBold);
int startrow = 2;
Iterator<Row> boldrowIterator = spreadsheet.iterator();
while (boldrowIterator.hasNext()) {
Row boldrow = boldrowIterator.next();
if (boldrow.getRowNum()==startrow) {
out.println(boldrow.getCell(9));
Cell boldcell = boldrow.getCell(9);
boldcell.setCellStyle(boldstyle);
startrow = startrow+1;
String Featuredescription = boldrow.getCell(9).getStringCellValue();
if (Featuredescription.contains("OR")) {
RichTextString richTextString = creationHelper.createRichTextString(Featuredescription);
String word = " OR ";
int startIndex = Featuredescription.indexOf(word);
int endIndex = startIndex + word.length();
out.println("Featuredescription: " + Featuredescription + startIndex + endIndex);
richTextString.applyFont(startIndex, endIndex, fontItalic);
boldcell.setCellValue(richTextString);
}
} }
EDIT
XSSFCellStyle linstyle = workbook.createCellStyle();
Font linfont = workbook.createFont();
linfont.setColor(IndexedColors.ORANGE.getIndex());
linstyle.setFont(linfont);
Iterator<Row> linrowIterator = spreadsheet.iterator();
while (linrowIterator.hasNext())
{
Row linrow = linrowIterator.next();
Iterator <Cell> lincellIterator = linrow.cellIterator();
if (linrow.getRowNum()==linrowcount) {
if (linrow.getCell(13).getStringCellValue().contains("LIN")) {
while (lincellIterator.hasNext())
{
Cell lincell = lincellIterator.next();
lincell.setCellStyle(linstyle);
} } linrowcount = linrowcount+1; }
}
I would recommend using a simple regular expression to find all the occurrences of AND and OR (note the spaces included in these strings). Doing this lets you easily determine the location of each occurrence within the overall string (the indexes of where each word starts and ends). You can use this to set everything to bold (like you are already doing) and then set each OR and AND to normal.
My code assumes your test text is in cell A1 - and that is the only cell I test. You can add back your looping logic to handle more cells.
You will also need:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
I have added comments to the code to explain specific lines:
FileInputStream file = new FileInputStream(new File("C:/temp/poi/rich_formatting_in.xlsx"));
Workbook wb = new XSSFWorkbook(file);
Sheet sheet = wb.getSheet("Sheet1");
CreationHelper creationHelper = wb.getCreationHelper();
Row row = sheet.getRow(0);
Cell cell = row.getCell(0);
String content = cell.getStringCellValue();
Font bold = wb.createFont();
bold.setBold(true);
Font normal = wb.createFont();
normal.setBold(false);
//normal.setItalic(true); // uncomment, if you need italics, as well.
RichTextString richStr = creationHelper.createRichTextString(content);
richStr.applyFont(bold); // set everything to bold
String regex = "( AND | OR )"; // note the spaces in the strings
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
// process each found group (one group for each AND and OR):
for (int i = 1; i <= matcher.groupCount(); i++) {
// matcher.start(i) finds where the start of the match is
// matcher.end(i) finds the position of the end of the match
// we can use these start and end positions to set that text to normal:
richStr.applyFont(matcher.start(i), matcher.end(i), normal);
}
}
// write the final string to the spreadsheet:
cell.setCellValue(richStr);
// write the spreadsheet to a file so we can see the results:
try (FileOutputStream out = new FileOutputStream(new File("C:/temp/poi/rich_formatting_out.xlsx"))) {
wb.write(out);
}
The results are:
The regex ( AND | OR ) is very basic - it assumes every occurrence of the words AND and OR surrounded by spaces are what need to be adjusted.

Charts don't appear in Google Sheets

I am using XSSF to make my charts in Excel.
The charts look perfectly fine in Microsoft Excel.
Problem:
When I import a chart into Google Sheets, the chart doesn't show up.
Is there a way to fix this?
I noticed if I made the chart in Microsoft Excel itself and import into Google Sheets, it works fine and I can see the chart. It seems like the problem occurs when the chart is made through Apache POI.
Here is the code:
void createChart(
XSSFSheet sheet, String chartName, double max,
XDDFDataSource<String> cat, XDDFNumericalDataSource<Double> val
) {
try {
final int graphRow1 = 6;
final int graphRow2 = 33;
final int graphCol1 = 4;
final int graphCol2 = 22;
final int logoRow1 = 30;
final int logoRow2 = 33;
final int logoCol1 = 19;
final int logoCol2 = 21;
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFClientAnchor anchor = drawing.createAnchor(
0, 0, 0, 0, graphCol1, graphRow1, graphCol2, graphRow2
);
XSSFChart chart = drawing.createChart(anchor);
chart.setTitleText(chartName);
chart.setTitleOverlay(false);
chart.getCTChart().getTitle()
.getTx()
.getRich()
.getPArray(0)
.getRArray(0)
.getRPr().setSz(1400);
CTRegularTextRun secondText = chart.getCTChart().getTitle()
.getTx()
.getRich()
.addNewP()
.addNewR();
secondText.setT("Net Analysis");
secondText.addNewRPr().setSz(1050);
secondText.getRPr().setI(true);
chart.getFormattedTitle().getParagraph(0).setTextAlignment(TextAlignment.CENTER);
chart.getFormattedTitle().getParagraph(1).setTextAlignment(TextAlignment.CENTER);
XDDFCategoryAxis leftAxis = chart.createCategoryAxis(AxisPosition.LEFT);
XDDFValueAxis bottomAxis = chart.createValueAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle("Volume");
bottomAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
XDDFBarChartData data =
(XDDFBarChartData) chart.createData(ChartTypes.BAR, leftAxis, bottomAxis);
data.setBarDirection(BarDirection.BAR);
data.setVaryColors(true);
XDDFChartData.Series series = data.addSeries(cat, val);
series.setTitle("", null);
chart.plot(data);
chart.getCTChartSpace()
.addNewSpPr()
.addNewSolidFill()
.addNewSrgbClr()
.setVal(HexConverter.parseHexBinary("52c3ba"));
//needed for image
//allows to modify anchor otherwise the anchor will resize chart.
drawing.createGroup(anchor);
int dx = Units.EMU_PER_CHARACTER * 6;
int dy = 3 * Units.EMU_PER_CHARACTER / 2;
anchor.setDx1(dx);
anchor.setDx2(dx);
anchor.setDy1(dy);
anchor.setDy2(dy);
anchor.setCol1(logoCol1);
anchor.setCol2(logoCol2);
anchor.setRow1(logoRow1);
anchor.setRow2(logoRow2);
drawing.createPicture(anchor, 0);
double tickMarkInterval = max % 20 == 0 ? max : max + (20 - (max % 20));
double maxUnit = tickMarkInterval / 20;
chart.getCTChart().getPlotArea().getBarChartArray(0).addNewGapWidth().setVal(10);
chart.getCTChart().getPlotArea().getValAxArray(0).addNewMajorUnit().setVal(maxUnit);
double scaleMax = max % maxUnit == 0 ? max : max + (maxUnit - (max % maxUnit));
chart.getCTChart().getPlotArea().getValAxArray(0).getScaling().addNewMax().setVal(scaleMax);
} catch (Exception e) {
e.printStackTrace();
}
}
cat and val are made here
XDDFDataSource<String> cat =
XDDFDataSourcesFactory.fromArray((String[]) categoryList.toArray());
XDDFNumericalDataSource<Double> val =
XDDFDataSourcesFactory.fromArray((Double[]) valueList.toArray());
The lay out of the XLSX is like this:
Row 1 has Category A.
Row 2 has Subcategory A1
Row 3 has Subcategory A2
Row 4 has Subcategory A3
Row 5 has Total of A
Row 7 has Category B.
Row 8 has Subcategory B1
Row 9 has Subcategory B2
Row 10 has Subcategory B3
Row 11 has Total of B
The chart is supposed to contain the name of Category A and B, and Total of A and B. So I assume this wouldn't work in google sheets then?

I use the poi to get the backgroundcolor,but it get same argbhex by different color

this is my test class:
public class testReadExcel {
public static void readExcel () throws Exception {
String path = "d:\\字体颜色1.xlsx";
File file = new File(path);
InputStream is = new FileInputStream(file);
Workbook wb = new XSSFWorkbook(is);
int numbersheets = wb.getNumberOfSheets();
Sheet sheet = wb.getSheetAt(0);
int cols = sheet.getPhysicalNumberOfRows();
for(int i = 0; i<cols;i++) {
Row row = sheet.getRow(i);
int cellnumber = row.getPhysicalNumberOfCells();
for(int j = 0;j<cellnumber;j++) {
Cell cell = row.getCell(j);
CellStyle cellstyle1 = ((XSSFCell)cell).getCellStyle();
XSSFCellStyle cellstyle = (XSSFCellStyle)cellstyle1;
XSSFColor b = cellstyle.getFillForegroundXSSFColor();
XSSFColor d = cellstyle.getFillBackgroundXSSFColor();
String c = b.getARGBHex();
String e = d.getARGBHex();
System.out.println("c "+c);
System.out.println("e "+e);
}
}
}
public static void main(String[] args) throws Exception{
readExcel();
and this is the color i used:
one color is #E46D0A ,the another is #F79646.
but when i get the color ,all of them become #F79646
c FFF79646
e null
c FFF79646
e null
This is the code's console ,how to get the right color?
Your question is confusing since your screenshot shows 6 cells which all should be processed by your code. But your shown result only shows results for two cells. I suspect this are the both first cells in your screenshot? If so, then the only reason for this output can be that the second cell has additional conditional formatting having pattern formatting set. So it has both, a cell style having fill formatting and the conditional formatting having pattern formatting. If this is the case, then the fill format of the conditional formatting is visible if the condition of the conditional formatting is fulfilled. Only if the condition of the conditional formatting is not fulfilled, then the cell style's fill format will be visible.
If the requirement is to get the visible fill color always, independent of whether it comes from cell style or conditional formatting, then this is a very expensive task. One would must test for each cell whether it has a conditional formatting and whether the condition is fulfilled.
The following complete code at least checks for each cell whether it has a conditional formatting having pattern formatting. If so, it prints all background colors of all conditional formattings which are applied to the cell. It does not check whether the condition is fulfilled or not. This is the expensive part of the task that nor is ToDo.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.ConditionalFormatting;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.FileInputStream;
import java.util.List;
import java.util.ArrayList;
class ReadExcelCellStyleFillColors {
static List<PatternFormatting> getConditionalPatternFormatting(Cell cell) {
List<PatternFormatting> patternFormattings = new ArrayList<PatternFormatting>();
Sheet sheet = cell.getSheet();
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
for (int i = 0; i < sheetCF.getNumConditionalFormattings(); i++) {
ConditionalFormatting conditionalFormatting = sheetCF.getConditionalFormattingAt(i);
CellRangeAddress[] cellRangeAdresses = conditionalFormatting.getFormattingRanges();
for (CellRangeAddress cellRangeAddress : cellRangeAdresses) {
if (cellRangeAddress.isInRange(cell)) {
for (int j = 0; j < conditionalFormatting.getNumberOfRules(); j++) {
ConditionalFormattingRule cFRule = conditionalFormatting.getRule(j);
PatternFormatting patternFormatting = cFRule.getPatternFormatting();
if (patternFormatting != null) patternFormattings.add(patternFormatting);
}
}
}
}
return patternFormattings;
}
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("ExcelExample.xlsx"));
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
System.out.println("This is cell " + new CellAddress(cell));
List<PatternFormatting> patternFormattings = getConditionalPatternFormatting(cell);
if (patternFormattings.size() > 0) {
System.out.println("This cell has conditional pattern formattings having background colors:");
for (PatternFormatting patternFormatting : patternFormattings) {
Color patternBGColor = patternFormatting.getFillBackgroundColorColor();
System.out.println(patternBGColor);
if (patternBGColor instanceof ExtendedColor) {
ExtendedColor extColor = (ExtendedColor)patternBGColor;
if (extColor.isThemed()) {
System.out.println("Theme color with index: " + extColor.getTheme());
} else {
System.out.println(extColor.getARGBHex());
}
}
}
}
CellStyle cellStyle = cell.getCellStyle();
Color fillFGColor = cellStyle.getFillForegroundColorColor();
System.out.println("This cell has fill foreground color:");
System.out.println(fillFGColor);
if (fillFGColor instanceof ExtendedColor) {
ExtendedColor extColor = (ExtendedColor)fillFGColor;
System.out.println(extColor.getARGBHex());
}
System.out.println();
}
}
workbook.close();
}
}

Sum if 1 criteria is text and 2 criteria is color in google sheet

I have used the script below:
function sumColoredCells(sumRange,colorRef) {
var activeRange = SpreadsheetApp.getActiveRange();
var activeSheet = activeRange.getSheet();
var formula = activeRange.getFormula();
var rangeA1Notation = formula.match(/\((.*)\,/).pop();
var range = activeSheet.getRange(rangeA1Notation);
var bg = range.getBackgrounds();
var values = range.getValues();
var colorCellA1Notation = formula.match(/\,(.*)\)/).pop();
var colorCell = activeSheet.getRange(colorCellA1Notation);
var color = colorCell.getBackground();
var total = 0;
for(var i=0;i<bg.length;i++)
for(var j=0;j<bg[0].length;j++)
if( bg[i][j] == color )
total=total+(values[i][j]*1);
return total;
}
and then used the formula
=IF(A2:A10,"A",sumColoredCells(B2:B10,D3))
In A Column there are is text value and B column there are yellow color with number value. I want the yellow color with number which correspond to A results a total sum in cell D2.
Check the screenshot below.

Why is my background color not applied (Aspose Cells)?

I'm trying to add a color to the background of my cells like so:
style.BackgroundColor = Color.LightBlue;
style.Pattern = BackgroundType.Solid;
In more context:
Cell shortNameHeaderCell = locationWorksheet.Cells[BYDCBYLOC_HEADING_ROW, SHORTNAME_BYDCBYLOC_COL];
shortNameHeaderCell.PutValue("Short Name");
style = cf.CreateStyle();
style.HorizontalAlignment = TextAlignmentType.Left;
style.VerticalAlignment = TextAlignmentType.Center;
style.Font.Name = fontForSheets;
style.Font.IsBold = true;
style.Font.Size = 12;
style.BackgroundColor = Color.LightBlue;
style.Pattern = BackgroundType.Solid;
shortNameHeaderCell.SetStyle(style);
Cell companyNameHeaderCell = locationWorksheet.Cells[BYDCBYLOC_HEADING_ROW, COMPANYNAME_BYDCBYLOC_COL];
companyNameHeaderCell.PutValue("Company Name");
companyNameHeaderCell.SetStyle(style);
Cell reasonDescHeaderCell = locationWorksheet.Cells[BYDCBYLOC_HEADING_ROW, REASONDESC_BYDCBYLOC_COL];
reasonDescHeaderCell.PutValue("Reason Description");
reasonDescHeaderCell.SetStyle(style);
Cell transTypeHeaderCell = locationWorksheet.Cells[BYDCBYLOC_HEADING_ROW, TRANSTYPE_BYDCBYLOC_COL];
transTypeHeaderCell.PutValue("Transaction Type");
style = cf.CreateStyle();
style.HorizontalAlignment = TextAlignmentType.Center;
style.Font.Name = fontForSheets;
style.Font.IsBold = true;
style.Font.Size = 12;
style.IsTextWrapped = true;
style.BackgroundColor = Color.LightBlue;
style.Pattern = BackgroundType.Solid;
transTypeHeaderCell.SetStyle(style);
Cell sumOfQtyOrdHeaderCell = locationWorksheet.Cells[BYDCBYLOC_HEADING_ROW, QTYORD_BYDCBYLOC_COL];
sumOfQtyOrdHeaderCell.PutValue("Sum of Qty Ord");
sumOfQtyOrdHeaderCell.SetStyle(style);
Cell sumOfQtyShippedHeaderCell = locationWorksheet.Cells[BYDCBYLOC_HEADING_ROW, QTYSHIPPED_BYDCBYLOC_COL];
sumOfQtyShippedHeaderCell.PutValue("Sum of Qty Shipped");
sumOfQtyShippedHeaderCell.SetStyle(style);
Yet, the light blue color is not applied:
Something is happening, though, because it looks like the midsections of the vertical lines bounding the cells have been erased. I don't know why, or what if any connection that has with the unbearable invisibleness of the light blue color. Before adding that code (first snippet), those smudges/erasings were not [in]visible.
Please note, if pattern is solid, Style.ForegroundColor should be used to paint the cell (or range). Moreover, if pattern is not solid or none, Style.BackgroundColor should be used for the same scenario.
Note: I am working as Developer Evangelist at Aspose.

Resources