pythonpython-3.xreportlabplatypus

overflow hidden on a Paragraph in Reportlab


I have a Table with 2 cells, inside of each one there is a Paragraph

from reportlab.platypus import Paragraph, Table, TableStyle
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import cm

table_style_footer = TableStyle(
            [
                ('LEFTPADDING', (0, 0), (-1, -1), 0),
                ('RIGHTPADDING', (0, 0), (-1, -1), 0),
                ('TOPPADDING', (0, 0), (-1, -1), 0),
                ('BOTTOMPADDING', (0, 0), (-1, -1), 0),
                ('BOX', (0, 0), (-1, -1), 1, (0, 0, 0)),
                ('VALIGN', (0, 0), (-1, -1), 'TOP'),
            ]
        )

style_p_footer = ParagraphStyle('Normal')
style_p_footer.fontName = 'Arial'
style_p_footer.fontSize = 8
style_p_footer.leading = 10

Table([
       [
        Paragraph('Send To:', style_p_footer), 
        Paragraph('Here should be a variable with long content', style_p_footer)
       ]
      ],
      [1.7 * cm, 4.8 * cm],
      style=table_style_footer
     )

I need hide the overflow content of paragraph , but the paragraph instead of hide the overflow content does a break line.


Solution

  • Reportlab doesn't seem to have a native support for hiding overflow, but we can achieve it by utilizing the breakLines function of a Paragraph. The breakLines functions returns an object that contains all the lines of the paragraph given a certain width, thus we can also use it to find the first line and discard everything else.

    Basically we need to do the following:

    1. Create a dummy paragraph
    2. Fetch the lines of the dummy
    3. Create a the actual paragraph based on the first line of the dummy

    Doing this in code looks like this:

    # Create a dummy paragraph to see how it would split
    long_string = 'Here should be a variable with long content'*10
    long_paragraph = Paragraph(long_string, style_p_footer)
    
    # Needed because of a bug in breakLines (value doesn't matter)
    long_paragraph.width = 4.8 * cm
    
    # Fetch the lines of the paragraph for the given width
    para_fragment = long_paragraph.breakLines(width=4.8 * cm)
    
    # There are 2 kinds of returns so 2 ways to grab the first line
    if para_fragment.kind == 0:
        shorted_text = " ".join(para_fragment.lines[0][1])
    else:
        shorted_text = " ".join([w.text for w in para_fragment.lines[0].words])
    
    # To make it pretty add ... when we break of the sentence
    if len(para_fragment.lines) > 1:
        shorted_text += "..."
    
    # Create the actual paragraph
    shorted_paragraph = Paragraph(shorted_text, style_p_footer)