Strange display of a table of radio buttons - itext

I am creating a form, in which there is a table of buttons. The following shows the idea:
Good OK Bad
Item1 [button] [button] [button]
Item2 [button] [button] [button]
Each row is a button group.
My program is able to work for a small table like the above. However, when rows or columns are more than one page to hold, the display is weird. This is my program:
PdfPTable table = new PdfPTable(colHeaders.size() + 1 );
table.setWidthPercentage(100);
PdfPCell cell;
table.setSpacingBefore(10);
table.setSpacingAfter(0);
table.setKeepTogether(false); //tested "true" different display error
//upper-left corner empty cell
cell = new CustomPdfPCell();
cell.setBackgroundColor(BaseColor.LIGHT_GRAY);
table.addCell(cell);
//header row
for (TableOfChoicesHeader c: colHeaders) {
String text = c.getText();
cell = new PdfPCell(new Phrase(text));
cell.setBackgroundColor(BaseColor.LIGHT_GRAY);
table.addCell(cell);
}
List<PdfFormField> radioGroups= new ArrayList<PdfFormField>();
//for each row
for (TableOfChoicesHeader r: rowHeaders) {
//row header
String rowText = r.getText();
cell = new PdfPCell(new Phrase(rowText));
cell.setBackgroundColor(BaseColor.LIGHT_GRAY);
table.addCell(cell);
//for the current row row
String fieldName = "question" + q.getId() +"_" + r.getId().toString();
PdfFormField radiogroup = PdfFormField.createRadioButton(writer, true);
radiogroup.setFieldName(fieldName);
radioGroups.add(radiogroup);
for (TableOfChoicesHeader c: colHeaders) {
cell = new PdfPCell();
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setPadding(5);
cell.setCellEvent(new CheckboxCellEvent(fieldName, r.getId() + "_" + c.getId()));
table.addCell(cell);
}
}
document.add(table);
for (PdfFormField g: radioGroups) {
writer.addAnnotation(g);
}
Here are the screenshots when table.setKeepTogether(false). The display is a little different but still strange if the value is true.
Page 1
Page 2
Update
By following Samuel's approach, I am able to see radio buttons displayed on the first page. However, the buttons on the first page got displayed on the second page. See the screenshots.
Update 2
I got it working by adding the following in MyCellField :
writer.addAnnotation(radiogroup);
instead of
PdfFormField field = radio.getRadioField();
writer.addAnnotation(field);
I cannot explain why. Thank Samuel and Bruno for their help!

Looking at your code again, is there any reason why you add the annotations for the radiobuttons all in one go at the end?.
Have you tried adding the annotation whenever you've added your row of cells? Something like this:
for (TableOfChoicesHeader r: rowHeaders) {
//row header
String rowText = r.getText();
cell = new PdfPCell(new Phrase(rowText));
cell.setBackgroundColor(BaseColor.LIGHT_GRAY);
table.addCell(cell);
//for the current row row
String fieldName = "question" + q.getId() +"_" + r.getId().toString();
PdfFormField radiogroup = PdfFormField.createRadioButton(writer, true);
radiogroup.setFieldName(fieldName);
radioGroups.add(radiogroup);
for (TableOfChoicesHeader c: colHeaders) {
cell = new PdfPCell();
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setPadding(5);
cell.setCellEvent(new CheckboxCellEvent(fieldName, r.getId() + "_" + c.getId()));
table.addCell(cell);
}
writer.addAnnotation(radiogroup)
}
EDIT:
As Bruno said, the examples for distributing a radio-group over multiple pages are RadioGroupMultiPage1 and RadioGroupMultiPage2. The examples for distributing a radio group across a table is found here: Distributing radio buttons of a radio field across multiple PdfCells.
EDIT 2, Electric Bogaloo:
Wipped up a quick example based on your code and the examples Bruno pointed out:
I basicly took your code frm the question above(with some stub-implementations for your custom data-classes), and used the MyCellField PdfCellEvent extension found in RadioGroupMultiPage2:
public MyCellField(PdfWriter writer, PdfFormField radiogroup, String value) {
this.writer = writer;
this.radiogroup = radiogroup;
this.value = value;
}
public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
try {
RadioCheckField radio = new RadioCheckField(writer, position, null, value);
PdfFormField field = radio.getRadioField();
writer.addAnnotation(field);
radiogroup.addKid(field);
} catch (IOException ex) {
// do nothing
} catch (DocumentException ex) {
// do nothing
}
}

Related

Header with 2 cells aligned in the same row, itextpdf 5.5.10

I have a row in my header, which looks good, but I need to add another String in the same row, so it is on the right side of it
When I try to add that String in the same cell, everything loses the alignment
private void addHeader(PdfWriter writer) {
PdfPTable tableHeader = new PdfPTable(2);
try {
// set defaults
header.setWidths(new int[] { 20, 12, 12 });
header.setTotalWidth(527);
header.setLockedWidth(true);
header.getDefaultCell().setFixedHeight(5);
header.getDefaultCell().setBorder(Rectangle.BOTTOM);
header.getDefaultCell().setBorderColor(BaseColor.LIGHT_GRAY);
// add text
PdfPCell text = new PdfPCell();
text.setPaddingBottom(12);
text.setPaddingLeft(8);
text.setBorder(Rectangle.BOTTOM);
text.setBorderColor(BaseColor.LIGHT_GRAY);
text.addElement(new Phrase("Hi", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
text.addElement(new Phrase("", new Font(Font.FontFamily.HELVETICA, 8)));
text.addElement(new Phrase("Hi" + "CVE-2017-2018", new Font(Font.FontFamily.HELVETICA, 9)));
header.addCell(text);
// add image
Image logo = Image.getInstance(App.class.getResource(LOGO_2));
header.addCell(logo);
PdfPCell cveTitle = new PdfPCell();
cveTitle.setPaddingBottom(15);
cveTitle.setPaddingLeft(8);
cveTitle.setBorder(Rectangle.BOTTOM);
cveTitle.setBorderColor(BaseColor.LIGHT_GRAY);
cveTitle.addElement(new Phrase("3 Cell", new Font(Font.FontFamily.HELVETICA, 16, Font.BOLD)));
header.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
header.addCell(cveTitle);
}
CVE-2010-2016
Is just what I want to do, leave it on the right side
Update
The solution was to add a new value to the array, corresponding to a new cell, and also instantiating PdfPCell again, thks
Just from the classname PdfPTable, I can tell the iText version you are using is pretty outdated.
Please consider switching to a newer version. Latest version is iText7.
I think what you're looking for is colspan and rowspan.
Have a look at the tutorial:
http://developers.itextpdf.com/examples/tables/clone-colspan-and-rowspan

Adding PdfPCell in iText PdfPtable doesnt work anymore

I have created several PdfPTable without problem, but now I dont know what is wrong. Fourth line doesnt displayed.
table = new PdfPTable(4);
table.setSpacingBefore(10);
columnWidths = new float[] {60,10,10,10};
table.setWidths(columnWidths);
PdfPCell cellFooter = new PdfPCell(new Phrase("Rows One", ARIAL_12_BOLD));
table.addCell(cellFooter);
for(int k=0; k<3; k++){
table.addCell("");
}
cellFooter = new PdfPCell(new Phrase("Row Two", ARIAL_12_BOLD));
table.addCell(cellFooter);
for(int k=0; k<3; k++){
table.addCell("");
}
cellFooter = new PdfPCell(new Phrase("Row Three", ARIAL_12_BOLD));
cellFooter.setColspan(4);
table.addCell(cellFooter);
// Row Four not displayed
for(int k=0; k<4; k++){
table.addCell("");
}
To answer, let me ask you this: How many pixels in height is an empty string?
The simplest way to get around this is to just add something. You should be able to just use:
table.addCell(" ");
However, if you're changing font sizes elsewhere the height might be different so you might want to explicitly set the font (and thus the height) of the empty cell:
table.addCell(new Phrase(" ", ARIAL_12_BOLD));
You could also explicitly define heights on cells but this is usually the easiest way.

iTextSharp - Adding content to a cell later in the code

I am using iTextSharp to generate an invoice PDF. For that I wish to display order number and total amount at top of PDF. However the actual amount is calculated during product displaying part.
To make it simple the report follows this structure
===========order number=========
===========total amount=========
//here I display the products and so total amount is calculated here.
==========end of report=========
To achieve this I am creating a cell for total amount like this
PdfPCell cell = new PdfPCell();
PdfPCell headingAmountCell = cell;
//add some components to cell, reinitialize them again with new cells etc.
//but still have first cell reference in headingAmountCell
//calculate total amount here.
.
.
.
.
headerAmountCell.AddElement(new Phrase("Total Amount:" + totalAmount.ToString());
.
.
.
However this doesn't work.
I can see order number at top but not total amount.
If you could please help, that'll be great.
Thanks in anticipation.
Regards
Anshul
UPDATE:
Here is a small portion of code to help understand the problem
//header
var headerTable = new PdfPTable(logoExists ? 2 : 1);
headerTable.WidthPercentage = 100f;
if (logoExists)
headerTable.SetWidths(new[] { 50, 50 });
float padding = 5f;
//logo
if (logoExists)
{
var logoFilePath = _pictureService.GetPictureUrl(logoPicture, 0, false);
var cellLogo = new PdfPCell(Image.GetInstance(logoFilePath));
cellLogo.Border = Rectangle.BOTTOM_BORDER;
cellLogo.BorderColorBottom = BaseColor.GRAY;
cellLogo.PaddingBottom = padding;
cellLogo.VerticalAlignment = Rectangle.ALIGN_TOP;
headerTable.AddCell(cellLogo);
}
//store info
var cell = new PdfPCell();
cell.Border = Rectangle.BOTTOM_BORDER;
cell.BorderColorBottom = BaseColor.GRAY;
cell.PaddingBottom = padding;
cell.HorizontalAlignment = Element.ALIGN_RIGHT;
cell.VerticalAlignment = Element.ALIGN_TOP;
//payment method
var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(order.PaymentMethodSystemName);
string paymentMethodStr = paymentMethod != null ? paymentMethod.GetLocalizedFriendlyName(_localizationService, lang.Id) : order.PaymentMethodSystemName;
PdfPCell headingAmountCell = cell;
if (!paymentMethodStr.Contains("COD") && order.PaymentStatus == global::Nop.Core.Domain.Payments.PaymentStatus.Paid)
{
cell.AddElement(new Paragraph("PREPAID", bigFont));
}
else if (paymentMethodStr.Contains("COD") && order.PaymentStatus == global::Nop.Core.Domain.Payments.PaymentStatus.Paid)
{
cell.AddElement(new Phrase("PAYMENT COLLECTED ON DELIVERY", bigFont));
}
else
{
cell.AddElement(new Paragraph("COLLECT ON DELIVERY", bigFont));
}
string order_number = order.GetOrderNumber();
cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Order#", lang.Id), order_number), bigFont));
var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore;
cell.AddElement(new Paragraph(String.Format("Order Date: {0}", _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc).ToString("D", new CultureInfo(lang.LanguageCulture))), font));
headerTable.AddCell(cell);
doc.Add(headerTable);
//THEN I PERFORM SOME PRODUCT DISPLAY PART WHERE I CALCULATE THE ORDERTOTAL THEN AT THE BOTTOM
//.
//.
..
headingAmountCell.AddElement(new Phrase(Math.Round(orderTotal) + "<-AMOUNT TO COLLECT")));

How do I add a radio group to a table cell using iTextSharp 4.1.6?

I'm trying to generate a dynamic survey as a PDF. The question text appears in the first cell, and the field appears in the 2nd cell. I have no problems when adding a text field or drop down field, but I cannot get a radio group to display. I am able to get a single radio button, but would like the entire group to display in the cell. Is this possible? And if so, how?
Here is a code sample of what I've tried thus far.
Table.AddCell(Question.TEXT + ":");
PdfFormField RadioGroup = PdfFormField.CreateRadioButton(ExportWriter, true);
RadioGroup.FieldName = "field" + Question.QUESTION_ID;
using (Entities _context = new Entities())
{
QuestionOptions = SURVEY.GetQuestionOptions(Question.QUESTION_ID, _context).ToList();
}
RadioCheckField Radio;
PdfFormField RadioField = null;
foreach (OPTIONS Option in QuestionOptions)
{
Radio = new RadioCheckField(ExportWriter, new Rectangle(40, 806 - count * 40, 60, 788 - count * 40), Option.OPTION_NAME, "option" + Option.OPTION_ID.ToString());
Radio.BackgroundColor = new GrayColor(0.8f);
Radio.CheckType = RadioCheckField.TYPE_CIRCLE;
RadioField = Radio.RadioField;
RadioField.SetWidget(new Rectangle(10, 20), PdfAnnotation.HIGHLIGHT_INVERT);
RadioGroup.AddKid(RadioField);
}
ExportWriter.AddAnnotation(RadioGroup);
Cell = new PdfPCell();
Events = new iTextSharp.text.pdf.events.FieldPositioningEvents(ExportWriter, RadioGroup);
Cell.CellEvent = Events;
Table.AddCell(Cell);
The issue is that when the radio buttons appear, they appear on the bottom left of the page, and not within the cell.
Thanks in advance!

iText - Strange column- / page changing behaviour with ColumnText

I am quite new to iText and trying to accomplish the following:
read a list of text files from local hd
arrange the texts of the files in a 2-column layout pdf file
add a consecutively numbered index before each text
I started with the MovieColumns1 example (http://itextpdf.com/examples/iia.php?id=64) and ended up with the following code:
final float[][] COLUMNS_COORDS = { { 36, 36, 296, 806 }, { 299, 36, 559, 806 } };
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, resultFile);
document.open();
ColumnText ct = new ColumnText(writer.getDirectContent());
ct.setSimpleColumn(COLUMNS_COORDS[0][0], COLUMNS_COORDS[0][1],
COLUMNS_COORDS[0][2], COLUMNS_COORDS[0][3]);
File textDir = new File("c:/Users/raddatz/Desktop/123/texts/");
File[] files = textDir.listFiles();
int i = 1;
int column = 0;
for (File file : files) {
String text = FileUtils.readFileToString(file, "UTF-8");
float yLine = ct.getYLine();
System.out.println("adding '" + file.getName() + "'");
PdfPCell theText = new PdfPCell(new Phrase(text, new Font(Font.HELVETICA, 10)));
theText.setBorder(Rectangle.NO_BORDER);
theText.setPaddingBottom(10);
PdfPCell runningNumber = new PdfPCell(new Phrase(new DecimalFormat("00").format(i++), new Font(
Font.HELVETICA, 14, Font.BOLDITALIC,
new Color(0.7f, 0.7f, 0.7f))));
runningNumber.setBorder(Rectangle.NO_BORDER);
runningNumber.setPaddingBottom(10);
PdfPTable table = new PdfPTable(2);
table.setWidths(new int[] { 12, 100 });
table.addCell(runningNumber);
table.addCell(theText);
ct.addElement(table);
int status = ct.go(true);
if (ColumnText.hasMoreText(status)) {
column = Math.abs(column - 1);
if (column == 0) {
document.newPage();
System.out.println("inserting new page with size :" + document.getPageSize());
}
ct.setSimpleColumn(
COLUMNS_COORDS[column][0], COLUMNS_COORDS[column][1],
COLUMNS_COORDS[column][2], COLUMNS_COORDS[column][3]);
yLine = COLUMNS_COORDS[column][3];
System.out.println("correcting yLine to: " + yLine);
} else {
ct.addElement(table);
}
ct.setYLine(yLine);
System.out.println("before adding: " + ct.getYLine());
status = ct.go(false);
System.out.println("after adding: " + ct.getYLine());
System.out.println("--------------------------------");
}
document.close();
Here you can see the result:
http://d.pr/f/NEmx
Looking at the first page of the resulting PDF I assumed everything was working out fine.
But on second page you can see the problem(s):
text #31 is not displayed completely (first line + index is cut / not in visible area)
text #46 is not displayed completely (first three lines + index is cut / not in visible area)
On page 3 everything seems to be ok again. I am really lost here.
-- UPDATE (2013-03-14) --
I have analyzed the contents of the PDF now. The problem is not that content is show in non-visible areas but that the content is not present in the pdf at all. The missing part of the content is exactly the one which would have fit in the previous column / page. So it seems like ColumnText.go(true) is manipulating the object passed by addElement() before. Can someone confirm this? If so: what can I do about it?
-- end UPDATE (2013-03-14) --
Looking forward to your reply
regards,
sven
Solved! As soon as ColumnText indicates a table will not fit the current column I reinitialize ct with a new instance of ColumnText and add the table again.
In other words:
Each instance of ColumnText is exactly dealing one column of my document.
if (ColumnText.hasMoreText(status) || mediaPoolSwitch) {
column = Math.abs(column - 1);
if (mediaPoolSwitch) {
currentMediaPool = mediapool;
column = 0;
}
if (column == 0) {
document.newPage();
writeTitle(writer.getDirectContent(), mediapool.getName());
}
ct = new ColumnText(writer.getDirectContent());
ct.addElement(table);
ct.setSimpleColumn(
COLUMNS_COORDS[column][0], COLUMNS_COORDS[column][1],
COLUMNS_COORDS[column][2], COLUMNS_COORDS[column][3]);
yLine = COLUMNS_COORDS[column][3];
LOG.debug("correcting yLine to: " + yLine);
} else {
ct.addElement(table);
}
ct.setYLine(yLine);
ct.go();