I am trying to merge two columns of one row to make one long line of text without any vertical separation by the cell borders. Here's what I have so far:
CellRangeAddress mergedRegion = new CellRangeAddress(0,0,0,1);
sheet.addMergedRegion(mergedRegion);
XSSFRow row = sheet.createRow(mergedRegion.getFirstRow());
XSSFCell cell = row.createCell(mergedRegion.getFirstColumn());
cell.setCellValue("some string");
Is this the correct way to set the cells contents? In my Junits do I refer to this merged region like this:
assertEquals(workbook.getSheetAt(0).getRow(mergedRegion.getFirstRow())
.getCell(mergedRegion.getFirstColumn()).getStringCellValue(),"some string");
It is probably easier to set the cell contents before you create the merged region. So for example you could:
Row row = sheet.createRow(1);
Cell cell = row.createCell(1);
cell.setCellValue("some string");
sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 5));
This would add a merged region in columns 1-5 of row 1
Related
I am creating an big excel using java class. Excel contains a merged cell which store string. Length of the string is very large, i am getting this string dynamically. I need to increase the height of the merged cell so that complete string will fit to that cell. I have tried using "wrap text", it wrap the text but doesn't increase the height of the merged cell due to which complete string is not visible in excel.
Java class i am using are:
XSSFWorkbook
XSSFSheet
XSSFRow
XSSFCell
XSSFCellStype
And other required dependent classes.
Is there a way how i can increase the height of the merge cell as per the cell value.
To give you an idea of the challenge how to calculate the needed row height.
We can get the column width in character widths for the columns using Sheet.getColumnWidth(int). But this is not really accurate since it only is for number glyphs: 1,2,3,4,5,6,7,8,9,0. In true type fonts there are glyphs (., |, l, ...) which need much less width. So this result will be as much more inaccurate as such less-width-glyphs are used in the text.
We might correct the column-width-in-chars by a factor. I use 5/4. But this is highly dependent on the language used.
Then we can calculate the needed row count and then get the needed row height by getting the default row height used for one line and multiply that with the needed row count .
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddress;
public class CreateExcelCellWrapText {
public static void main(String[] args) throws Exception {
XSSFWorkbook workbook = new XSSFWorkbook();
CellStyle cellstyle = workbook.createCellStyle();
cellstyle.setWrapText(true);
Sheet sheet = workbook.createSheet();
//__________________________not merged = height is auto sized
Row row = sheet.createRow(0);
Cell cell = row.createCell(2);
cell.setCellValue("String cell content\nhaving line wrap.");
cell.setCellStyle(cellstyle);
//__________________________merged = height is not auto sized
row = sheet.createRow(2);
cell = row.createCell(2);
cell.setCellValue("String cell content\nhaving line wrap.");
cell.setCellStyle(cellstyle);
CellRangeAddress cellRangeAddress = new CellRangeAddress(2, 2, 2, 3);
sheet.addMergedRegion(cellRangeAddress);
//__________________________merged with calculated height
row = sheet.createRow(4);
String text = "String cell content\nhaving line wrap.\nIt has new line marks and then a long text without new line marks.\nFollowed by short text part.\n\n\nGreetings";
cell = row.createCell(2);
cell.setCellValue(text);
cell.setCellStyle(cellstyle);
cellRangeAddress = new CellRangeAddress(4, 4, 2, 3);
sheet.addMergedRegion(cellRangeAddress);
//get the column width in character widths for the merged columns
//this is not really accurate since it only is for number glyphs: 1,2,3,4,5,6,7,8,9,0
//in true type fonts there are glyps (., |, l, ...) which need much less width
int colwidthinchars = (sheet.getColumnWidth(2) + sheet.getColumnWidth(3)) / 256;
System.out.println(colwidthinchars);
//correct the colwidthinchars by a factor 5/4 (highly dependent on the language used)
colwidthinchars = Math.round(colwidthinchars * 5f/4f);
System.out.println(colwidthinchars);
//calculate the needed rows dependent on the text and the column width in character widths
String[] chars = text.split("");
int neededrows = 1;
int counter = 0;
for (int i = 0; i < chars.length; i++) {
counter++;
if (counter == colwidthinchars) {
System.out.println("new line because of charcter count");
neededrows++;
counter = 0;
} else if ("\n".equals(chars[i])) {
System.out.println("new line because of new line mark");
neededrows++;
counter = 0;
}
}
System.out.println(neededrows);
//get default row height
float defaultrowheight = sheet.getDefaultRowHeightInPoints();
System.out.println(defaultrowheight);
row.setHeightInPoints(neededrows * defaultrowheight);
workbook.write(new FileOutputStream("CreateExcelCellWrapText.xlsx"));
workbook.close();
}
}
This works because default font and font size is used. The challenge increases up to infinity when different fonts and different font sizes are used ;-).
See How to get the needed height of a multi line rich-text field (any font, any font size) having defined width using Java? for an example rendering the formatted text in a JTextPane to get the preferred height.
I want to modify an existing xlsm file with apache POI.
As I only have to change single cells I don't want to loop over the whole sheet, but all the examples I have found so far suggest to loop over all the rows and over all cells in a row, checking if the current row/col-index matches the one to be changed.
Is there no "random access" mode to get a single cell by its coordinates directly? Event the promising getCell method of the CellUtil class needs a row object instead of just an integer coordinate.
The Excel file format is a (normally) sparse file format, so unused + unstyled rows and cells are normally skipped from the file. So, you do need to check for null values when fetching rows and cells. But, other than that, you can fetch cells pretty much directly. You can use the CellReference class to turn an Excel-style set of co-ordinates (eg B3) into a POI-style one (eg row=2, column=1), then fetch
CellReference ref = new CellReference("B3");
Workbook workbook = WorkbookFactory.create(new File("input.xls"));
Sheet sheet = workbook.getSheetAt(0);
Row r = sheet.getRow(ref.getRow());
if (r == null) {
// Handle this whole row being empty
} else {
Cell c = r.getCell(ref.getCol(), Row.RETURN_BLANK_AS_NULL);
if (c == null) {
// Handle this cell being empty
} else {
// Do something with the cell
}
}
Depending on how you want to handle missing rows or cells, you can make it shorter, but that'll be specific to your needs
You get first the row from the sheet and then get the cell at x,y from it:
Row myRow = getRow(int x, sheet);
Cell myCell = getCell(myRow, int y);
On page I have table, and at the end of the page I have one paragraph, if rows contains small count of rows paragraph must still stay at the end of the page, but if rows too much and table take more than one page paragraph must be just after the table end. At first it looks easy for me and I just set minimum height for PdfPCell which contains table, but then I discover if page is split on pages minimum height apply to each part of table, and because of it paragraph isn't under the table on second page. Is there any solution for it?
I found one not very good solution for this problem, I've added one column to the table, which width it too small and it isn't visible for users, in this column I've add table with two rows, for first row I set minimum height which I need, here the code for creating this additional column
private PdfPCell createMinHeight(float minH) {
PdfPCell cell = new PdfPCell();
PdfPTable table = new PdfPTable(1);
cell.setBorder(Rectangle.NO_BORDER);
table.getDefaultCell().setBorder(Rectangle.NO_BORDER);
table.setHeaderRows(0);
PdfPCell firstRow = new PdfPCell();
firstRow.setBorder(Rectangle.NO_BORDER);
firstRow.setMinimumHeight(minH);
firstRow.setPadding(0);
table.addCell(firstRow);
table.addCell("");
cell.setPadding(0);
cell.addElement(table);
return cell;
}
If I understand you right, you don't want the paragraph splits? You can use setKeepTogether(boolean); for the elements you need:
paragraph.setKeepTogether(true);
or
table.setKeepTogether(true);
Working on a calendar projcet and using iText to generate a pdf to print appointments. I can plot a cell with a colspan, and a cell with a rowspan, but I can't combine it. Table has width of 4 cells. I want to achieve something like this:
(A)(B)(C)(C)
(D)(E)(C)(C)
so (1,1), (1,2) and (2,1) (2,2) are regular cells. But there should be a cell in (1,3) covering (1,3) (1,4) (2,3) and (2,4) thus having a colspan of 2 AND a rowspan of 2.
Current code:
PdfPTable table = new PdfPTable(4);
PdfPCell cell = new PdfPCell(new Phrase(" 1,1 "));
table.addCell(cell);
cell = new PdfPCell(new Phrase(" 1,2 "));
table.addCell(cell);
PdfPCell cell23 = new PdfPCell(new Phrase("multi 1,3 and 1,4"));
cell23.setColspan(2);
cell23.setRowspan(2);
table.addCell(cell23);
cell = new PdfPCell(new Phrase(" 2,1 "));
table.addCell(cell);
cell = new PdfPCell(new Phrase(" 2,2 "));
table.addCell(cell);
// 2,3 and 2,4 should be filled because 1,3 has rowspan 2 and colspan 2.
//table.completeRow(); //no effect
However that generates an error:
ExceptionConverter: java.io.IOException: The document has no pages.
If i don't start creating the second row, it just plots fine ( 1 row, and cell on (1,3) has a colspan of 2. Since there is no second row, the rowspan(2) has no effect.
Any help is appreciated. Thanks
At first sight, I'd say: you get a "document has no pages" exception because you're not adding any content to the document. I don't see:
document.add(table);
anywhere in your code snippet.
I have copy/pasted your code into a full example and I posted the full example here: ColspanRowspan. The resulting PDF looks like this:
This seems to be the desired behavior. I can only think of two differences: (1) you're forgetting to add the actual table (which was my initial answer), or (2) you are using a mighty old version of iText in which rowspan wasn't fully supported.
I want to increase the width of the column of excel sheet. as the i am writing trough code is long.
and I need to drag the column manually to see the full text.
I did this –
HSSFRow dataRow = sampleDataSheet.createRow(0);
HSSFCellStyle cellStyle = setHeaderStyle(sampleWorkbook);
cellStyle.setWrapText(true);
***sampleDataSheet.autoSizeColumn(1000000);***
But its not changing anything..
This should work. However,
sampleDataSheet.autoSizeColumn(1000000);
auto-expands column 1000000.
If you want to auto-expand column 0(the first column), use:
sampleDataSheet.autoSizeColumn(0);
To auto-expand column 0 to 9(the first 10 columns):
for (int i=0; i<10; i++){
sampleDataSheet.autoSizeColumn(i);
}
Also, you should create all your rows and fill them with content first, before you call autoSizeColumn(so the column gets the width of the value with the broadest width).
(If you want to set the column width to a fixed value, use HSSFSheet.setColumnWidth(int,int) instead.)
// We can set column width for each cell in the sheet
sheet.setColumnWidth(0, 1000);
sheet.setColumnWidth(1, 7500);
sheet.setColumnWidth(2, 7500);
// By applying style for cells we can see the total text in the cell for specified width
HSSFCellStyle cellStyle = workBook.createCellStyle();
cell.setCellStyle(cellStyle );
cellStyle.setWrapText(true);
sheet.autoSizeColumn(columnNumber) works. this will resize the column to the largest cell length.