Wrap text in a table reportlab?

Question:

I use a table but, I draw in in a canvas to control the position of the flowables, this because I have a template in a pdf, an I merge with pyPDF.

The wrap is done in a table but the text go up, not down that’s what I hope.

c is the canvas

Code

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph, Table
from reportlab.lib.units cm

width, height = A4
styles = getSampleStyleSheet()

def coord(x, y, unit=1):
    x, y = x * unit, height -  y * unit
    return x, y

descrpcion = Paragraph('long paragraph', styles["Normal"])
partida = Paragraph('1', styles["Center"])
candidad = Paragraph('120', styles["Center"])
precio_unitario = Paragraph('$52.00', styles["right"])
precio_total = Paragraph('$6240.00', styles["right"])

data= [[partida, candidad, descrpcion, precio_unitario, precio_total]]
table = Table(data, colWidths=[2.05 * cm, 2.7 * cm, 9.6 * cm,
                               2.65 * cm, 2.7 * cm])

c = canvas.Canvas(PDF, pagesize=A4)
table.wrapOn(c, width, height)
table.drawOn(c, *coord(1.8, 9.6, cm))
c.save()
Asked By: Alquimista

||

Answers:

I know that Postscript’s reference is the lower, left corner. I’m guessing that PDF is the same, so you subtract from the y value to go down. Print the beginning and ending “y” values in the function to see how they are changing and adjust the “y” value depending on the length of the sentence. And how does the function know what “height” is? I use ReportLab but could probably help with a specific example if you care to post one.

Answered By: Woooee

AutoReply:

def coord(x, y, height, unit=1):
    x, y = x * unit, height -  y * unit
    return x, y

w, h = table.wrap(width, height)
table.wrapOn(c, width, height)
table.drawOn(c, *coord(ml - 0.05, y + 4.6, height - h, cm))

the trick is in the “height – h”, h is the height of the table and this depend of the content of the table

Answered By: Alquimista

The description text went up as you wrap it in a styles[“Normal”] You can try to wrap your text in a styles[“BodyText”] This will allow your text to align themselves according to the width of the cell you specify. You could also include formatting which is similar to HTML text formatting.

Then use TableStyle to format the content in the table, for example, color text, center paragraph, span rows/columns and so on.

I edited the code above to a working version (example):

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph, Table, TableStyle
from reportlab.lib.enums import TA_JUSTIFY, TA_LEFT, TA_CENTER
from reportlab.lib import colors

width, height = A4
styles = getSampleStyleSheet()
styleN = styles["BodyText"]
styleN.alignment = TA_LEFT
styleBH = styles["Normal"]
styleBH.alignment = TA_CENTER

def coord(x, y, unit=1):
    x, y = x * unit, height -  y * unit
    return x, y

# Headers
hdescrpcion = Paragraph('''<b>descrpcion</b>''', styleBH)
hpartida = Paragraph('''<b>partida</b>''', styleBH)
hcandidad = Paragraph('''<b>candidad</b>''', styleBH)
hprecio_unitario = Paragraph('''<b>precio_unitario</b>''', styleBH)
hprecio_total = Paragraph('''<b>precio_total</b>''', styleBH)

# Texts
descrpcion = Paragraph('long paragraph', styleN)
partida = Paragraph('1', styleN)
candidad = Paragraph('120', styleN)
precio_unitario = Paragraph('$52.00', styleN)
precio_total = Paragraph('$6240.00', styleN)

data= [[hdescrpcion, hcandidad,hcandidad, hprecio_unitario, hprecio_total],
       [partida, candidad, descrpcion, precio_unitario, precio_total]]

table = Table(data, colWidths=[2.05 * cm, 2.7 * cm, 5 * cm,
                               3* cm, 3 * cm])

table.setStyle(TableStyle([
                       ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
                       ('BOX', (0,0), (-1,-1), 0.25, colors.black),
                       ]))

c = canvas.Canvas("a.pdf", pagesize=A4)
table.wrapOn(c, width, height)
table.drawOn(c, *coord(1.8, 9.6, cm))
c.save()
Answered By: Nicholas TJ

Even though this is an old question, it’s still relevant for those who don’t want to use a document template.

As mentioned, you can use ‘VALIGN’ to wrap text within the cells, but there is another hack if you want to further control the table elements on the canvas.

Before:
enter image description here

table=Table(data, style=[
        ('INNERGRID', (0,0), (-1,-1), 0.25, black),
        ('BOX', (0,0), (-1,-1), 0.25, black),
        ('VALIGN',(0,0),(-1, -1),'TOP'),
        ])

table.wrapOn(self.c, (inch*8)-50, self.height)   
table.drawOn(self.c, *self.coord(x=1, y=20, unit=cm))

Now adding two components:

  1. rowHeights attribute
  2. _argH for finer editing of the row heights

After:
enter image description here

from reportlab.lib.units import mm, cm, inch

 table=Table(data, rowHeights = 8*mm, style=[
        ('INNERGRID', (0,0), (-1,-1), 0.25, black),
        ('BOX', (0,0), (-1,-1), 0.25, black),
        ('VALIGN',(0,0),(-1, -1),'TOP'),
        ])

    table._argH[0] = 1*cm + 4   
    table._argH[1] = 1*cm + 4   
    table._argH[2] = 1*cm + 4   
    table._argH[3] = 1*cm + 4   
    table._argH[4] = 1*cm + 4   

table.wrapOn(self.c, (inch*8)-50, self.height)   
table.drawOn(self.c, *self.coord(x=1, y=20, unit=cm))

In this case my maximum cell values = 5 which is denoted as 0 – 4 cells.

You can find the number of cell values used in the table like so:

print(len(table.cellvalues))
Answered By: Conor
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.