1

I am trying to add a legend as a single line (Paragraph) to a chart drawn as an image on my page. The legend needs to have the descriptor (Chunk) followed by a line of the appropriate color to match the chart. When I search on how to draw a line, it appears that I can only do it using absolute positioning. Is there some way to draw the line following the descriptor regardless of where the descriptor will be in the paragraph and on the page? It will also be followed by one or more additional descriptors (Chunks) each with an appropriately colored line. TIA.

String[] monitors=Configuration.getInstance().getMonitorIds();
Chunk title=new Chunk("Legend: ");
title.setFont(legendFont);
Paragraph legend=new Paragraph(title);
for (String entry : monitors) {
    Monitor mon=Configuration.getInstance().getMonitor(entry);
    Chunk name=new Chunk(mon.getName());
    Font nameFont=new Font(FontFamily.TIMES_ROMAN, 20.f, Font.BOLD,new BaseColor(mon.getColor().getRGB()));
    name.setFont(nameFont);
// What goes here to draw the line???               
    legend.add(name);
}
document.add(legend);

Update after a comment from @mkl:

I think I found what you meant in this article: Drawing diagonal line in a cell of a table in iTExt?. So I added the following to my helper to draw a horizontal line rather than the diagonal in the article:

@Override
public void onGenericTag(PdfWriter writer_, Document document_, Rectangle rectangle_, String tag_) {
    PdfContentByte canvas = writer_.getDirectContent();
    canvas.saveState();
    Monitor mon=Configuration.getInstance().getMonitor(tag_);
    canvas.setColorStroke(new BaseColor(mon.getColor().getRGB()));
    canvas.moveTo(Rectangle.LEFT,Rectangle.ALIGN_CENTER);
    canvas.lineTo(Rectangle.RIGHT,Rectangle.ALIGN_CENTER);
    canvas.stroke();
    canvas.restoreState();
}

Then I changed my code (along with some other tweaking) to include the onGenericTag Chunk but it was not a direct thing as I interpreted the article. I can't put just a Chunk in a Cell. Here is my current code:

String[] monitorIds=Configuration.getInstance().getMonitorIds();
PdfPTable leg=new PdfPTable(monitorIds.length+2);
Paragraph p=new Paragraph("Legend: ",legendFont);
PdfPCell title=new PdfPCell(p);
title.setBorder(Rectangle.NO_BORDER);
leg.addCell(title);
for (String entry : monitorIds) {
    Monitor mon=Configuration.getInstance().getMonitor(entry);
    Font nameFont=new Font(FontFamily.TIMES_ROMAN, 14.f, Font.BOLD,new BaseColor(mon.getColor().getRGB()));
    Paragraph name=new Paragraph(mon.getName(),nameFont);
    PdfPCell c=new PdfPCell(name);
        c.setBorder(Rectangle.NO_BORDER);
    leg.addCell(c);
    Chunk line=new Chunk();
    line.setGenericTag(entry);
    c=new PdfPCell(new Paragraph(line));
    c.setBorder(Rectangle.NO_BORDER);
    leg.addCell(c);
}
document.add(leg);

Unfortunately the line does not show up. What am I doing wrong? TIA.

After all the suggestions

Thanks for them. I've decided to try to stick with the OnGenericTag. I think it is more appropriate, at this point, to start a new thread. Drawing a Line in a PdfPCell Using OnGenericTag

Wt Riker
  • 514
  • 12
  • 24
  • Have you looked into custom events? I would assume you can implement your goal using them. – mkl Dec 02 '17 at 20:16
  • Events? Isn't that for end of page processing and such? I'm thinking this is maybe some kind of PdfTemplate thing but I'll take a look. – Wt Riker Dec 02 '17 at 21:56

1 Answers1

1

If you want to draw a line, you can use a Chunk consisting of non-breaking spaces:

Chunk line = new Chunk("\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0");

Now use the setUnderline() method to draw a line. See the API docs.

You can invoke this method on the same chunk as many times as you need lines (e.g. in some cases you might want to draw a double line). You can pass the color as a parameter, including the thickness of the line, either as an absolute value, or as a value relative to the font size, and including the y position with respect to the baseline of the text:

public Chunk setUnderline(BaseColor color,
    float thickness, float thicknessMul,
    float yPosition, float yPositionMul,
    int cap)

This is what the parameters are about:

  • color - the color of the line or null to follow the text color
  • thickness - the absolute thickness of the line
  • thicknessMul - the thickness multiplication factor with the font size
  • yPosition - the absolute y position relative to the baseline
  • yPositionMul - the position multiplication factor with the font size
  • cap - the end line cap. Allowed values are PdfContentByte.LINE_CAP_BUTT, PdfContentByte.LINE_CAP_ROUND and PdfContentByte.LINE_CAP_PROJECTING_SQUARE

You can also use a separator (see for instance the LineSeparator class in the API docs)? See the Separator examples.

You can use such a separator as a line in-between two lines of text:

But you can also use such a separator as a Chunk. See for instance Create Index File(TOC) for merged pdf using itext library in java where we have:

p.add(new Chunk(new DottedLineSeparator()));

You could define a special LineSeparator class for each color, and wrap it inside a Chunk.

I see that you've tried the onGenericTag() functionality, but were unsuccessful. If you really need that functionality make sure that you declare the page event to the PdfWriter.

See for instance: How to draw a line every 25 words?

In this example, we have a page event class named WordCount, and we add an instance of that class to the PdfWriter object:

writer.setPageEvent(new WordCounter());

If you forget this, nothing will happen (for a very logical reason).

If you want a line to be drawn, you also need to be sure the Chunk isn't empty, or you draw a line from point x,y to punt x,y (that's an invisible dot, not a line).

An alternative, is to create a PdfTemplate, draw a line to it, and wrap that PdfTemplate inside an image. See How do I align a graphic in iTextPDF? or take a look at the RectangleInCell example:

PdfTemplate template = writer.getDirectContent().createTemplate(120, 80);
template.setColorFill(BaseColor.RED);
template.rectangle(0, 0, 120, 80);
template.fill();
writer.releaseTemplate(template);
table.addCell(Image.getInstance(template));

In this example, we create a template measuring 120 by 80 user units, and we draw a red rectangle on that template. We release the template (the content is written to the output), and we add the template to a PdfPTable as an Image.

Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • I do NOT want to underline anything. I thought most people would know what a legend on a chart is. A legend displays the line type, color etc. with a descriptor so the reader can relate what line applies to what it represents on the accompanying chart. So my objective is to create a cell that contains the text of a descriptor followed by a cell containing a line of the same color as in the chart. I did add the helper class but didn't show it. I have that working for other events so I just showed the added method for the generic tag as the rest is irrelevant to my question. – Wt Riker Dec 03 '17 at 18:26
  • Thanks for rearranging my OP. I didn't think of that and I didn't know how to add formatted code to a comment. I guess I can't. Finally, I am using itext 5 rather than 7 because of this: https://stackoverflow.com/questions/47593083/migrating-jfreechart-from-itext-5-to-7 – Wt Riker Dec 03 '17 at 18:26
  • So basically, you want a vector image? That's done with a `PdfTemplate` wrapped in an `Image` (and the image can be wrapped in a `Chunk` if needed). You are trying to do this using a `Chunk`, but nothing is shown because the `Chunk` is empty. Change `Chunk line=new Chunk();` into `Chunk line=new Chunk("\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0");` and you should see a line. Note that my answer is still valid: you can use `setUnderline()` on the `line` object, and the line will also be shown. Use the `y` value to position the line. That's much easier than using page events. – Bruno Lowagie Dec 03 '17 at 19:01
  • I've updated my answer. Basically there are 4 different ways to achieve what you want. (1.) Add a `Chunk` with lines drawn with `setUnderline()`, (2.) Add a `Chunk` with lines drawn with a separator class, (3.) Use `onGenericTag()` to draw content, and (4.) draw content in a `PdfTemplate`. – Bruno Lowagie Dec 03 '17 at 19:20
  • Thanks for the suggestions and my apologies for being unclear. I decided to sick with onGenericTag and updated the OP. I am starting a new thread that is more appropriate for the new direction this thread has taken. – Wt Riker Dec 04 '17 at 12:17