Is there a way to hide excel formula using Apache POI - excel

I want to populate column B value on basis of value selected in Drop down of column A. Working fine, with the help of VLOOKUP formula in all cells of column B. But now I want to hide the formula for column B cells, in order to avoid the formula alteration by user(even by mistake).
But formula should work as expected even after hiding it.
Is there any way to achieve it using Apache POI. Or Is there any other way to achieve auto population on basis of selection in drop down using Apache POI.
Thankyou in advance.

Hiding formulas is part of the cell style in Excel. So the simplest answer would be to use CellStyle.setHidden(true).
But that will only hide the formula but not prevent the formula alteration by user. This is what sheet protection is for. So you would need a combination of the both.
Following complete example shows that. Fomulas in C2:C4 are hidden and protected.
import java.io.FileOutputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
public class CreateExcelDefaultColumnStyleNotLockedAndLockedHideFormulas {
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook(); String filePath = "./CreateExcelDefaultColumnStyleNotLockedAndLockedHideFormulas.xlsx";
//Workbook workbook = new HSSFWorkbook(); String filePath = "./CreateExcelDefaultColumnStyleNotLockedAndLockedHideFormulas.xls";
CellStyle lockedHideFormulas = workbook.createCellStyle();
lockedHideFormulas.setLocked(true);
lockedHideFormulas.setHidden(true);
CellStyle notLocked = workbook.createCellStyle();
notLocked.setLocked(false);
Sheet sheet = workbook.createSheet();
Row row = sheet.createRow(0);
Cell cell = null;
for (int c = 0; c < 3; c++) {
cell = row.createCell(c);
cell.setCellValue("Col " + (c+1));
}
for (int r = 1; r < 4; r++) {
row = sheet.createRow(r);
for (int c = 0; c < 2; c++) {
cell = row.createCell(c);
cell.setCellValue(r * (c+1));
cell.setCellStyle(notLocked);
}
cell = row.createCell(2);
cell.setCellFormula("A" + (r+1) + "*B" + (r+1));
cell.setCellStyle(lockedHideFormulas);
}
sheet.setDefaultColumnStyle(0, notLocked);
sheet.setDefaultColumnStyle(1, notLocked);
sheet.setDefaultColumnStyle(2, notLocked);
sheet.protectSheet("");
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}

Related

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

C# NPOI set cell style to Text / string 1-19 is formatted as a date / disable any formating

I am creating an excel, when i write some values example 1-19, when I open the excel doc, i see 1-19, but if i click on it then excel tries to format it as a date
IS THERE A WAY to force the sheet to not use any formulas or formatting?
I have checked and the dataformat is string.
private void Test1(ref ISheet worksheet, string[] array, IWorkbook workbook, int iRow, XSSFFont font2)
{
var format = HSSFDataFormat.GetBuiltinFormats();
ICellStyle _TextCellStyle = workbook.CreateCellStyle();
_TextCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#");
IRow file = worksheet.CreateRow(iRow);
int iCol = 0;
for (int y = 0; y < array.Length; y++)
{
ICellStyle style = workbook.CreateCellStyle();
style.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index;
//style.DataFormat = HSSFDataFormat.
ICell cell = file.CreateCell(iCol, CellType.String);
cell.SetCellValue(array[y]);
style.SetFont(font2);
// cell.CellStyle = style;
var getst = cell.CellType;
cell.CellStyle = _TextCellStyle;
iCol++;
getst = cell.CellType;
}
}
Your data remains in "General" format even after you are using correct format string "#" as per documentation. Some time library methods don't work in NPOI so you'll have to try different approach.
You can try one of these
_TextCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("text"); //Instead of "#"
Or prefix single quote for data when writing it for excel file like '1-19

I want to get some particular cell from excel using selenium webdriver

I am working with excel file with selenium webdriver. I can read the data from excel successfully but I want to get some particular Cell address and value from excel sheet using selenium webdirver.
Can anyone help on this?
Thanks in Advance.
Here is the Code.
String FilePath="D:\\ProUtility_Automation\\Transformation Logic.xls";
try {
Workbook wrk1 = Workbook.getWorkbook(new File(
FilePath));
Sheet sheet1 = wrk1.getSheet(0);
int totalNoOfRows = sheet1.getRows();
int totalNoOfCols = sheet1.getColumns();
//String a[][] = new String[1000][1000];
for (int row = 0; row < totalNoOfRows; row++) {
for (int col = 0; col < totalNoOfCols; col++) {
System.out.print(sheet1.getCell(col, row).getContents() + "\t");
}
System.out.println();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Here is the code for reading particular cell value from excel, please import the right POI jars in your project, so that this code works correctly
private static XSSFCell Cell;
private static XSSFRow Row;
public static String getCellData(int RowNum, int ColNum) throws Exception{
try{
Cell = ExcelWSheet.getRow(RowNum).getCell(ColNum);
String CellData = Cell.getStringCellValue();
return CellData;
}catch (Exception e){
return"";
}
}
If you want the 2nd row, 3rd column cell value simply pass the parameters getCellData(1,2)---------> excel rows and columns start from (0,0)

How to override PrimeFaces p:dataExporter wrongly exporting numbers as text in Excel?

The PrimeFace p:dataExporter tag exports numeric data as text by default, which results in a cell with a green triangle in the upper left corner. This can be seen in the PrimeFaces showcase example as well, if you click the Excel export under the cars table.
How can I override this default to make sure my numeric columns are not exported as text? I tried using the postProcessor attribute pointing to my method that sets the Excel format for all the data cells using POI API but that did not take effect (did not change anything):
public void formatExcel(Object doc) {
HSSFWorkbook book = (HSSFWorkbook)doc;
HSSFSheet sheet = book.getSheetAt(0);
HSSFRow header = sheet.getRow(0);
int colCount = header.getPhysicalNumberOfCells();
int rowCount = sheet.getPhysicalNumberOfRows();
HSSFCellStyle numStyle = book.createCellStyle();
numStyle.setDataFormat((short)1);
for(int rowInd = 1; rowInd < rowCount; rowInd++) {
HSSFRow row = sheet.getRow(rowInd);
for(int cellInd = 1; cellInd < colCount; cellInd++) {
HSSFCell cell = row.getCell(cellInd);
String val = cell.getStringCellValue();
cell.setCellStyle(numStyle);
}
}
}
I also tried
cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
but that gives me
java.lang.IllegalStateException: Cannot get a numeric value from a text cell
So that means that all data is indiscriminately exported as text and then you can't even change it afterwards.
This is what ended up working for me. It is far from elegant but it works:
HSSFCellStyle intStyle = book.createCellStyle();
intStyle.setDataFormat((short)1);
HSSFCellStyle decStyle = book.createCellStyle();
decStyle.setDataFormat((short)2);
HSSFCellStyle dollarStyle = book.createCellStyle();
dollarStyle.setDataFormat((short)5);
for(int rowInd = 1; rowInd < rowCount; rowInd++) {
HSSFRow row = sheet.getRow(rowInd);
for(int cellInd = 1; cellInd < colCount; cellInd++) {
HSSFCell cell = row.getCell(cellInd);
//This is sortof a hack to counter PF exporting all data as text
//We capture the existing value as string, convert to int,
//then format the cell to be numeric and reset the value to be int
String strVal = cell.getStringCellValue();
//this has to be done to temporarily blank out the cell value
//because setting the type to numeric directly will cause
//an IllegalStateException because POI stupidly thinks
//the cell is text because it was exported as such by PF...
cell.setCellType(HSSFCell.CELL_TYPE_BLANK);
cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
strVal = strVal.replace(",", StringUtils.EMPTY);
if(strVal.indexOf('.') == -1) {
//integer
//numStyle.setDataFormat((short)1);
int intVal = Integer.valueOf(strVal);
cell.setCellStyle(intStyle);
cell.setCellValue(intVal);
} else {
//double
if(strVal.startsWith("$")) {
strVal = strVal.replace("$", StringUtils.EMPTY);
//numStyle.setDataFormat((short)5);
cell.setCellStyle(dollarStyle);
} else {
//numStyle.setDataFormat((short)2);
cell.setCellStyle(decStyle);
}
double dblVal = Double.valueOf(strVal);
cell.setCellValue(dblVal);
}
}
}
In your postProcessor, you nowhere set the value of the cell to an integer. You set the type, but not the value. Setting the type is not enough. You have to convert value to a number and set it again

POI: Append rows to existing workbook

Using XSSFWorkbook, is it possible to append rows to an existing sheet? I am doing multiple writes (which was a PITA to solve due to a bug) and while I can write out new sheets multiple times, it does not appear that I can append.
What I am currently doing is the following:
Read sheet to my workbook.
Load workbook.
Append rows to workbook in memory
Write out again.
4 Does not appear to work, just ignores it completely!
I am aware that SXSSFWorkbook exists, but attempting to convert my existing XSSFWorkbook into a streaming workbook creates corruption upon write.
Is it possible to solve this concundrum?
Update: Changed code based on suggestion, but getting stream closed error.
Code: (The physical rows returns correctly, but nothing gets written out)
private void writeToSheetMultipleTimes(SXSSFWorkbook wb,
ReportTemplateStructure appA, File wbFile)
{
Sheet sheet = wb.getSheetAt(0);
log.info("Attempting multi-write to sheet: " + sheet.getSheetName());
for(int i = 0; i < 10; i++)
{
Row row = sheet.getRow(i);
if (row == null) {
row = sheet.createRow(i);
}
Cell cell = row.getCell(0, Row.CREATE_NULL_AS_BLANK);
cell.setCellValue("Written value:" + i);
int numRows = sheet.getPhysicalNumberOfRows();
log.info("Current row count: " + numRows);
try{
XSSFWorkbook xssfBook = (XSSFWorkbook)writeOutAndReadBack(wb);
wb.dispose();
wb = new SXSSFWorkbook(xssfBook);
} catch (Exception e)
{
log.error("Unable to perform multiple write to same sheet", e);
}
}
}
public Workbook writeOutAndReadBack(Workbook wb) {
if(!(wb instanceof SXSSFWorkbook)) {
throw new IllegalArgumentException("Expected an instance of SXSSFWorkbook");
}
Workbook result;
try {
FileOutputStream baos = new FileOutputStream(streamingWorkBookFile);
wb.write(baos);
InputStream is = new FileInputStream(streamingWorkBookFile);
result = new XSSFWorkbook(is);
} catch (IOException e) {
throw new RuntimeException(e);
}
return result;
}
You appear to be always making changes to Sheet 0, but you're calling createRow every time. This won't go well if there's already something there, eg on your second pass! You either need to add a new Sheet every time, or check if the Row is there with a call to getRow(int) first and only create if it is null.
If we look at your code snippet:
Sheet sheet = wb.getSheetAt(0);
for(int i = 0; i < 10; i++)
{
Row row = sheet.createRow(i);
Cell cell = row.createCell(0);
That should either be something like:
Sheet sheet = wb.createSheet();
for(int i = 0; i < 10; i++)
{
Row row = sheet.createRow(i);
Cell cell = row.createCell(0);
Or you should check first and only create missing rows/cells, eg
Sheet sheet = wb.getSheetAt(0);
for(int i = 0; i < 10; i++)
{
Row row = sheet.getRow(i);
if (row == null) {
row = sheet.createRow(i);
}
Cell cell = row.getCell(0, Row.CREATE_NULL_AS_BLANK);
You can use getPhysicalNumberOfRows() Method in XSSFSheet class to get last updated row number. Now create a new row by incrementing this value to append new data.

Resources