简体   繁体   中英

How to resize a chart using XSSF (Apache POI 3.8)?

I am wondering whether there is a way to resize a chart using Apache POI (XSSF). Currently I am using an Excel template, which has a chart that changes when more data is inserted using namedRanges.

Everything works fine, the only troubles I'm facing are:

  • The chart always stays the same size, so if there are more entries, it gets cluttered making the chart kind of useless.
  • I am using dates, but I am not able to represent the date as day/month(17/10) on the chart. Basically instead of 04/01/2001, it writes 36982.

The purpose of the workbook is to list several jobs and check whether they took longer on a given date, the graph is for helping to identify the ocurrences of longer elapsed times. The jobs runtime might range from seconds to hours.

This is the code I am using:

 package le_package.poi_tests.xssflibrary; import java.io.*; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Name; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class POIReadFile { public static void main(String[] args) { try { String jobName = "I am a job"; String jobParent = "I am your father, Job."; int rowNum = 40; int deface = 4; //Open Excel as OOXML XSSFWorkbook currentWorkbook = new XSSFWorkbook( OPCPackage.open("include/excelTemplate.xlsx")); //Get sheet in position 0 Sheet currentSheet = currentWorkbook.getSheetAt(0); //Get sheet name for processing String sheetName = currentSheet.getSheetName(); //Set values for headers currentSheet.getRow(1).getCell(0).setCellValue(jobName); currentSheet.getRow(1).getCell(1).setCellValue(jobParent); for (int i=0; i<rowNum; i++) { //Create row in a given position Row newRow = currentSheet.createRow(i+deface); //Create cell within row Cell newCell0 = newRow.createCell(0); Cell newCell1 = newRow.createCell(1); Cell newCell2 = newRow.createCell(2); String cellDate = ""; /* Set CellType * 0 - Numeric | 1 - String | 2 - Formula | 3 - Blank | 4 - Boolean | 5 - Error */ newCell0.setCellType(0); cellDate = "3/"+(i+1)+"/2001 00:00:00"; //Convert text into date Date currentCellDate = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse(cellDate); //System.out.println(currentCellDate.toString()+"--"+cellDate); //Set CellValue newCell0.setCellValue(currentCellDate); cellDate = "4/"+(i+1)+"/2001 00:00:00"; currentCellDate = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse(cellDate); //System.out.println(currentCellDate.toString()+"--"+cellDate); newCell1.setCellType(0); newCell1.setCellValue(currentCellDate); //setCellFormula sets the formula to be evaluated by excel, it doesn't need to start with '=' newCell2.setCellFormula("A" + (i+deface+1) + "-B" + (i+deface+1)); } //Search for named range Name rangeCell = currentWorkbook.getName("startRange"); //Set new range for named range String reference = sheetName + "!$A$" + ( deface+1 ) + ":$A$" + ( rowNum+deface ); //Assigns range value to named range rangeCell.setRefersToFormula(reference); rangeCell = currentWorkbook.getName("endRange"); reference = sheetName + "!$B$"+(deface+1) + ":$B$" + (rowNum+deface); rangeCell.setRefersToFormula(reference); rangeCell = currentWorkbook.getName("elapsedTime"); reference = sheetName + "!$C$"+(deface+1) + ":$C$" + (rowNum+deface); rangeCell.setRefersToFormula(reference); //Create a fileStream to write into a file FileOutputStream newExcelFile = new FileOutputStream(jobName+".xlsx"); //Write Stream currentWorkbook.write(newExcelFile); //Close New Excel File newExcelFile.close(); } catch (Exception e) { System.out.println("AAAAARGH, I was wounded by the following exception!:"); e.printStackTrace(); System.out.println("Sorry, your program is dead :("); } } } 

Is it possible to do what I need?

Thanks.

*Note: I am not asking to create a chart from the scratch, I only need to resize the one the template has, and change some cells to date instead of the number that is written.

After researching how xlsx works, I was able to find how to get it done.

//Call the partiarch to start drawing
XSSFDrawing drawing = ((XSSFSheet)currentSheet).createDrawingPatriarch();
//Create CTMarket for anchor
CTMarker chartEndCoords = CTMarker.Factory.newInstance();
//The coordinates are set in columns and rows, not pixels.
chartEndCoords.setCol(column);
//Set Column offset
chartEndCoords.setColOff(0);
chartEndCoords.setRow(row);
chartEndCoords.setRowOff(0);
//drawing.getCTDrawing().getTwoCellAnchorArray(0).setFrom(chartStartCoords);
drawing.getCTDrawing().getTwoCellAnchorArray(0).setTo(chartEndCoords);

/*
    This line of code allows to resize the chart:
        The Patriarch is what allows to get control over the drawings, since
        a chart is considered a graph in xlsx you can access it with getCTDrawing.
        Each graph is stored in the tag getTwoCellAnchorArray, where the array position
        is the chart you have; for example getTwoCellAnchorArray(3) would refer to the
        forth graph within the sheet.

        Each getTwoCellAnchorArray has several properties as FROM and TO, which define
        where the existing graph starts and ends.   
*/

If you have any comments, let me know.

  1. Give your date cells, date format. Apache poi date format

  2. POI cannot modify graphics AFAIK.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM