How do I insert a new blank line inside a PdfPTable column. \n and n number of spaces has not done the trick for me. This is the java code I am working with.
chtbc_report1_table.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{"H.B.G", "Some Value", "lbs/kg", "Adult M : 120lbs \n Adult F : 90lbs"},
.....
.....
//Other rows
},
new String [] {
"Investigation", "Result", "Unit", "Weight"
}
));
I want to put a new line between "Adult M : 120lbs **\n** Adult F : 90lbs"
UPDATE
This is the code I have used for creating a PdfPTable
document.open();
PdfPTable pdfTable = new PdfPTable(chtbc_report1_table.getColumnCount());
for (int rows = 0; rows < chtbc_report1_table.getRowCount(); rows++) {
for (int cols = 0; cols < chtbc_report1_table.getColumnCount(); cols++) {
pdfTable.addCell(chtbc_report1_table.getModel().getValueAt(rows, cols).toString());
}
}
float[] columnWidths_pdfTable = new float[]{30f, 25f, 40f, 50f};
pdfTable.setWidths(columnWidths_pdfTable);
document.add(pdfTable);
document.close()
Any suggestions would help.
Oh, that is quite simple indeed. Try the following as the same works for me :-
Table Contents
jTable1.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{"Lorem Ipsum", "Next Line here \n, Another new line\n, Two new lines\n\nI will end here"},
{"Lorem Ipsum", "Another cell to demonstrate \n\n\n\n4 New lines above and two below \n\n"}
},
new String [] {
"Text", "Long Text"
}
));
Let me know, if that worked. And the PdfPtable should be the same.
Related
i'm trying to place a loop inside a TableModel to loop all the articles inside an arraylist to insert all the rows inside the table so i can add it to the form and show all the articles to the user
public class ListArticlesForm extends Form {
public ListArticlesForm(Form previous) {
setTitle("List all articles");
SpanLabel sp = new SpanLabel();
sp.setText(ServiceTask.getInstance().getAllArticles().toString());
ArrayList<Articles> articles = ServiceTask.getInstance().getAllArticles();
TableModel model = new DefaultTableModel(new String[]{"name", "description", "label", "quantity", "rating", "rate"},
new Object[][]{
{
// I WANT TO PLACE A FOR HERE (this is showing only the first row !
articles.get(0).getName(), articles.get(0).getDescription(), articles.get(0).getLabel(), articles.get(0).getQuantity(), articles.get(0).getRating(), add(createStarRankSlider())
},});
Table table = new Table(model);
add(table);
getToolbar().addMaterialCommandToLeftBar("", FontImage.MATERIAL_ARROW_BACK, e -> previous.showBack());
}
}
You can't create an array as a for loop inside the array. You need to do it a line sooner.
Object[][] rows = new Object[articles.size()][];
for(int iter = 0 ; iter < rows.length ; iter++) {
rows[iter] = new Object[] {
articles.get(iter).getName(), articles.get(0).getDescription(), articles.get(0).getLabel(), articles.get(0).getQuantity(), articles.get(0).getRating(), add(createStarRankSlider())
};
}
TableModel model = new DefaultTableModel(new String[]{"name", "description", "label", "quantity", "rating", "rate"}, rows);
now after i Run the project the table rows are displayed correctly except the rank stars
the show outside the table and inside the colonne a text appears:
the function for the star rank creation is :
private Slider createStarRankSlider(int id) {
Slider starRank = new Slider();
starRank.setEditable(true);
starRank.setMinValue(0);
starRank.setMaxValue(10);
int fontSize = Display.getInstance().convertToPixels(3);
Font fnt = Font.createTrueTypeFont("Handlee", "Handlee-Regular.ttf").
derive(fontSize, Font.STYLE_PLAIN);
Style s = new Style(0xffff33, 0, fnt, (byte) 0);
Image fullStar = FontImage.createMaterial(FontImage.MATERIAL_STAR, s).toImage();
s.setOpacity(100);
s.setFgColor(0);
Image emptyStar = FontImage.createMaterial(FontImage.MATERIAL_STAR, s).toImage();
initStarRankStyle(starRank.getSliderEmptySelectedStyle(), emptyStar);
initStarRankStyle(starRank.getSliderEmptyUnselectedStyle(), emptyStar);
initStarRankStyle(starRank.getSliderFullSelectedStyle(), fullStar);
initStarRankStyle(starRank.getSliderFullUnselectedStyle(), fullStar);
starRank.setPreferredSize(new Dimension(fullStar.getWidth() * 5, fullStar.getHeight()));
starRank.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
ServiceTask.getInstance().UpdateRank(id,starRank.getIncrements());
Dialog.show("Success","thank you for rating our product",new Command("OK"));
}
});
return starRank;
}
I have a JSON which has entries that look like
[{ "key": { "keyLabel": "Label1" }, "specs": [{ "specKey":
"spec1", "specValue": ["s11"] }, { "specKey": "spec2",
"specValue": ["s12"] }] },
{ "key": { "keyLabel":
"Label2" }, "specs": [{ "specKey": "spec1", "specValue":
["s21"] }, { "specKey": "spec3", "specValue":
["s22"] }] }]
Spec Keys present changes on the basis of KeyLabel value. As you can see above if if KeyLabel = Label1, spec1 and spec2 are present. If KeyLabel = Label2, spec1 and spec3 are present
I want to create a CSV/Excel using this such that header/top row as following columns
KeyLabel, spec1, spec2, spec3 (basically union of all specKeys)
Label1, s11,s12
Label2, s21, ,s22
So, the challenging part is that at the time of writing to file, I need to write under in the appropriate column.
Any thoughts on if there are any csv/excel libraries which make this easier. Naive way does seem very elegant - which is to store the ordered list of headers and basic on key write commas and values so that values are in write column
I think you don't need specific library for doing that.
You should only need some common library jackson poi-ooxml
First, you should read json string to POJO object (ref: http://www.jsonschema2pojo.org/)
List examples = new ObjectMapper().readValue(json, new TypeReference>() {});
Seconds, collect header
List header = examples
.stream()
.map(Example::getSpecs)
.flatMap(Collection::stream)
.map(Spec::getSpecKey)
.distinct()
.collect(Collectors.toList());
header.add(0, "Key");
Next, use POI library write excel file
final XSSFWorkbook workbook = new XSSFWorkbook();
final XSSFSheet sheet = workbook.createSheet(WorkbookUtil.createSafeSheetName("sheetname"));
// Headers
Row row = sheet.createRow(0);
for (int index = 0; index < headers.size(); index++) {
row.createCell(index).setCellValue(headers.get(index));
}
// Content
int startRow = 1;
for (Example object : objects) {
row = sheet.createRow(startRow++);
// key label
row.createCell(0).setCellValue(object.getKey().getKeyLabel());
// spec
for (int index = 1; index < headers.size(); index++) {
String speckey = headers.get(index);
String value = object.getSpecs().stream().filter(e -> e.getSpecKey().equals(speckey)).findAny().map(Spec::getSpecValue).orElse(Collections.emptyList()).toString();
row.createCell(index).setCellValue(value);
}
}
FileOutputStream fileOut = new FileOutputStream("D:\\poi-generated-file.xlsx");
try {
workbook.write(fileOut);
} finally {
fileOut.close();
workbook.close();
}
It only example code. You should modify and update to better.
I have a table in the docx template.
Depending on the number of objects, I have to duplicate the table as many times as I have objects. Duplicate tables must be after the table from the template.
I have several tables in the template that should behave like this.
XmlCursor take the place of the first table from the template and put the next one there. I want to insert the next table after the previous one, which I added myself, but xmlcursor does not return the table item I added, but returns "STARTDOC"
XmlCursor cursor = docx.getTables().get(pointer).getCTTbl().newCursor();
cursor.toEndToken();
while (cursor.toNextToken() != XmlCursor.TokenType.START) ;
XWPFParagraph newParagraph = docx.insertNewParagraph(cursor);
newParagraph.createRun().setText("", 0);
cursor.toParent();
cursor.toEndToken();
while (cursor.toNextToken() != XmlCursor.TokenType.START) ;
docx.insertNewTbl(cursor);
CTTbl ctTbl = CTTbl.Factory.newInstance();
ctTbl.set(docx.getTables().get(numberTableFromTemplate).getCTTbl());
XWPFTable tableCopy = new XWPFTable(ctTbl, docx);
docx.setTable(index + 1, tableCopy);
Not clear what you are aiming for with the cursor.toParent();. And I also cannot reproduce the issue having only your small code snippet. But having a complete working example may possible help you.
Assuming we have following template:
Then following code:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
public class WordCopyTableAfterTable {
static XmlCursor setCursorToNextStartToken(XmlObject object) {
XmlCursor cursor = object.newCursor();
cursor.toEndToken(); //Now we are at end of the XmlObject.
//There always must be a next start token.
while(cursor.hasNextToken() && cursor.toNextToken() != org.apache.xmlbeans.XmlCursor.TokenType.START);
//Now we are at the next start token and can insert new things here.
return cursor;
}
static void removeCellValues(XWPFTableCell cell) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
for (int i = paragraph.getRuns().size()-1; i >= 0; i--) {
paragraph.removeRun(i);
}
}
}
public static void main(String[] args) throws Exception {
//The data. Each row a new table.
String[][] data= new String[][] {
new String[] {"John Doe", "5/23/2019", "1234.56"},
new String[] {"Jane Doe", "12/2/2019", "34.56"},
new String[] {"Marie Template", "9/20/2019", "4.56"},
new String[] {"Hans Template", "10/2/2019", "4567.89"}
};
String value;
XWPFDocument document = new XWPFDocument(new FileInputStream("WordTemplate.docx"));
XWPFTable tableTemplate;
CTTbl cTTblTemplate;
XWPFTable tableCopy;
XWPFTable table;
XWPFTableRow row;
XWPFTableCell cell;
XmlCursor cursor;
XWPFParagraph paragraph;
XWPFRun run;
//get first table (the template)
tableTemplate = document.getTableArray(0);
cTTblTemplate = tableTemplate.getCTTbl();
cursor = setCursorToNextStartToken(cTTblTemplate);
//fill in first data in first table (the template)
for (int c = 0; c < data[0].length; c++) {
value = data[0][c];
row = tableTemplate.getRow(1);
cell = row.getCell(c);
removeCellValues(cell);
cell.setText(value);
}
paragraph = document.insertNewParagraph(cursor); //insert new empty paragraph
cursor = setCursorToNextStartToken(paragraph.getCTP());
//fill in next data, each data row in one table
for (int t = 1; t < data.length; t++) {
table = document.insertNewTbl(cursor); //insert new empty table at position t
cursor = setCursorToNextStartToken(table.getCTTbl());
tableCopy = new XWPFTable((CTTbl)cTTblTemplate.copy(), document); //copy the template table
//fill in data in tableCopy
for (int c = 0; c < data[t].length; c++) {
value = data[t][c];
row = tableCopy.getRow(1);
cell = row.getCell(c);
removeCellValues(cell);
cell.setText(value);
}
document.setTable(t, tableCopy); //set tableCopy at position t instead of table
paragraph = document.insertNewParagraph(cursor); //insert new empty paragraph
cursor = setCursorToNextStartToken(paragraph.getCTP());
}
paragraph = document.insertNewParagraph(cursor);
run = paragraph.createRun();
run.setText("Inserted new text below last table.");
cursor = setCursorToNextStartToken(paragraph.getCTP());
FileOutputStream out = new FileOutputStream("WordResult.docx");
document.write(out);
out.close();
document.close();
}
}
leads to following result:
Is that about what you wanted to achieve?
Please note how I insert the additional tables.
Using table = document.insertNewTbl(cursor); a new empty table is inserted at position t. This table is placed into the document body. So this table must be taken for adjusting the cursor.
Then tableCopy = new XWPFTable((CTTbl)cTTblTemplate.copy(), document); copys the template table. Then this copy is filled with data. And then it is set into the document at position t using document.setTable(t, tableCopy);.
Unfortunately apache poi is incomplete here. XWPFDocument.setTable only sets the internally ArrayLists but not the underlying XML. XWPFDocument.insertNewTbl sets the underlying XML but only using an empty table. So we must do it that ugly complicated way.
I have a big DTO with exactly 234 fields, and I have to display values of each fields of this DTO in a column of an Excel file created with apache-poi.
This is my code :
// Blank workbook
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Export values");
// Get the Entity
Simfoot simEntity = simService.findById(simId).get();
Row row = sheet.createRow(0);
row.createCell(1).setCellValue("Consult our values");
// and after this I want to convert my Simfoot object to a column in the third column ( so creteCell(2) ..... ).
I want to have in my first column : nothing , in my second only the String display ( "Consult our values" ) and in my third column I need to have my 234 fields. With an field ( the value of the field ) in one cell. So, 234 rows displaying one value in the third column.
I hope that it is clear.
Thanks a lot for your help.
Using some reflection:
// Blank workbook
XSSFWorkbook workbook = new XSSFWorkbook();
final Sheet sheet = workbook.createSheet("Export values");
// Get the Entity
final Simfoot simEntity = simService.findById(simId).get();
Row row = sheet.createRow(0);
row.createCell(1).setCellValue("Consult our values");
// and after this I want to convert my Simfoot object to a column in the third column ( so creteCell(2) ..... ).
Arrays.stream(simEntity.getClass().getDeclaredMethods())
.filter(m -> m.getName().startsWith("get") && m.getParameterTypes().length == 0 && !void.class.equals(m.getReturnType()))
.forEach(m -> {
try {
Object value = m.invoke(simEntity, null);
Row r = sheet.createRow(sheet.getLastRowNum()+1);
r.createCell(2).setCellValue(value == null ? "" : value.toString());
}
catch (Exception ex) {
// Manage Exception....
}
});
I'll add a method on Simfoot to return all the values:
public List<String> getAllValues() {
return Arrays.asList(getAtt1(), getAtt2(), .. , getAtt234());
}
Then create a row per attribute, and then you can merge the rows of the first 2 columns. Example here with 6 attributes:
int n = 6; // would be 234 for you
XSSFCellStyle styleAlignTop = workbook.createCellStyle();
styleAlignTop.setVerticalAlignment(VerticalAlignment.TOP);
Row row;
for(int i=0; i<n; i++) {
row = sheet.createRow(i);
if(i==0) {
Cell cell = row.createCell(1);
cell.setCellStyle(styleAlignTop);
cell.setCellValue("Consult our values");
}
row.createCell(2).setCellValue(simEntity.getAllValues().get(i));
}
sheet.addMergedRegion(new CellRangeAddress(0, n-1, 0, 0));
sheet.addMergedRegion(new CellRangeAddress(0, n-1, 1, 1));
It shows like this:
Another way to list your attributes would be to use Reflection but I find it very clunky:
Simfoot simEntity = new Simfoot("pap", "pep", "pip", "pop", "pup", "pyp");
for(PropertyDescriptor propertyDescriptor :
Introspector.getBeanInfo(Simfoot.class).getPropertyDescriptors()) {
System.out.println(propertyDescriptor.getReadMethod().invoke(simEntity));
}
Outputs:
pap
pep
pip
pop
pup
pyp
class Simfoot
so you have to filter out getClass and any other unwanted methods and getters
I am attempting to write an excel sheet using POI and hashMaps. My code successfully creates and populates an excel sheet but not all of the information is written to the sheet. In debug mode it seems to write 5 key, value pairs and then loops to the start at key [0]. Can someone tell me where the mistake is in my logic?
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet(make + " sheet");
int rowNum = 0;
ConcurrentHashMap <Integer, String[] > data = new
ConcurrentHashMap<Integer, String[]>();
data.put(rowNum++, new String[] {"VIN", "Make", "Model", "Year",
"Major Group", "Caption", "Cap Filter", "Illustration",
"Illus Filter", "PNC", "Part Name", "Part Number", "Quantity",
"Part Filter"});
for (Part p : plist){
String PNC = p.getPNC();
String quantity = p.getQuantity();
if(vFilterId.contains(p.getId())) {
data.put(rowNum++ , new String[] {vinId, make,
model, year, group, caption, capFilter, illusName,
iFilter, PNC, p.getName(), p.getPartNumber(),
quantity, "NONFILTERED"});
} else {
data.put(rowNum++ , new String[] {vinId, make,
model, year, group, caption, capFilter, illusName,
iFilter, PNC, p.getName(), p.getPartNumber(),
quantity, "NONFILTERED"});
}
}
int rowIndex = 0;
Set<Integer> keyset = data.keySet();
for (Integer key : keyset) {
Row row = sheet.createRow(rowIndex++);
Object[] objArr = data.get(key);
int cellIndex = 0;
for (Object obj : objArr) {
Cell cell = row.createCell(cellIndex++);
cell.setCellValue((String) obj);
}
}
try {
FileOutputStream fos = new FileOutputStream(outputFile);
workbook.write(fos);
fos.close();
System.out.println("XLS sheet written.");
} catch (IOException e) {
e.printStackTrace();
}
}
return ReturnConstants.SUCCESS;
}
Thanks in advance!
You're using a map to store data representing rows in a table. You'd be better off using a List since maps are generally not sorted (i.e. the order of the entries might change over time).
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet(make + " sheet");
List<String[]> data = new ArrayList<String[]>();
data.add(new String[] {"VIN", "Make", "Model", "Year",
"Major Group", "Caption", "Cap Filter", "Illustration",
"Illus Filter", "PNC", "Part Name", "Part Number", "Quantity",
"Part Filter"});
for (Part p : plist){
String PNC = p.getPNC();
String quantity = p.getQuantity();
if(vFilterId.contains(p.getId())) {
data.add(new String[] {vinId, make,
model, year, group, caption, capFilter, illusName,
iFilter, PNC, p.getName(), p.getPartNumber(),
quantity, "NONFILTERED"});
} else {
data.add(new String[] {vinId, make,
model, year, group, caption, capFilter, illusName,
iFilter, PNC, p.getName(), p.getPartNumber(),
quantity, "NONFILTERED"});
}
}
for (int rowIndex=0; rowIndex<data.size(); rowIndex++) {
Row row = sheet.createRow(rowIndex);
Object[] objArr = data.get(rowIndex);
int cellIndex = 0;
for (Object obj : objArr) {
Cell cell = row.createCell(cellIndex++);
cell.setCellValue((String) obj);
}
}
It's hard to determine without debugging your code, but from what you described it seems like your keyset variable contains only 3 entries, which is why you are outputting only 3 rows. So the first thing I would do would be to display (using System.out.println) data.size() and keyset.size() to see how big they are. I am guessing one or both are only of size 3.
Did you show all the relevant code? I think perhaps not, because, for example, your if statement seems redundant as you output the same thing regardless of whether you execute the if code or else clause.
I do agree with the first answer that there is no need to use a HashMap; an ArrayList will work just as well. But, as you discovered, that has nothing to do with why you are only seeing 3 rows.
Sorry I can't be more helpful, but I think some debugging on your part with System.out.println will go a long way in discovering what the problem is.