febrero 15, 2014

ReportLab: Platypus - PageTemplate y DocTemplate (12)

Los niveles más altos en platypus son los PageTemplates y DocTemplates. Los DocTemplates están formados por un conjunto de PageTemplates.

Los DocTemplates son expresado a trávez de BaseDocTemplate, que es una clase que implementa la maquinaria básica para el formateo del documento. Posee un método build que procesa una lista de Flowables (obviamente, estos almacenados en los frames, y los frames en los pagetemplates) y un método addPageTemplates que agrega los pagetemplates. De esta forma se llega a producir el documento PDF a alto nivel.

Los argumentos principales del BaseDocTemplate son los siguientes:

BaseDocTemplate( nombreArchivo,  # Nombre de nuestro pdf
                    pagesize=defaultPageSize,  # Tamaño de página
                    pageTemplates=[],  # Lista de pagetemplates
                    showBoundary=0,  # Para mostrar el borde
                    leftMargin=inch,  # Magen izquierdo
                    rightMargin=inch,  # Margen derecho
                    topMargin=inch,  # Margen superior
                    bottomMargin=inch,  # Margen inferior
                    title=None,  # Titulo del pdf
                    author=None,  # Autor del pdf
                    )



El SimpleDocTemplate (from reportlab.platypus import SimpleDocTemplate), es una platilla de documento predefinida, cuyo uso por lo general se da en relación con el canvas. No usa una lista de pagetemplates, pero nos asigna uno. Además, en su método build, se puede usar onFirstPage y onLaterPages, como modelos de primera página y páginas posteriores. (ejemplo)

En cuanto a los PageTemplates, que son contenedores de los Frames, poseen los siguientes argumentos:

PageTemplate(id=None,  # Identificador
                          frames=[],  # Lista de frames
                          onPage=_doNothing,  # Por lo general es usado como encabezado
                          onPageEnd=_doNothing  # Por lo general es usado como pie de página
                         )

Tanto onPage como onPageEnd deben ser llamados por una función, que tiene la estructura siguiente:

def XXX(canvas, documento)

Esas dos rutinas, en si tienen el objetivo de dibujar, partes estáticas en las páginas, que no son fluibles como los flowables (No-Flowables). Es por eso, que por lo general su uso se centra en encabezado, pies de página, marcas de agua.

Ahora, veamos el ejemplo de cómo usar el pagetemplate y doctemplate


#-*- coding:utf-8 -*-
import os

#Librerias reportlab a usar:
from reportlab.platypus import (BaseDocTemplate, Frame, Paragraph, 
                    NextPageTemplate, PageBreak, PageTemplate)
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import A4


#NIVEL 1: CREAMOS LOS CANVAS
#===========================   
#Creamos los canvas para el pie de página y encabezado, que serán fijos
def encabezado(canvas,doc):
    canvas.saveState()
    canvas.setFont('Times-Roman',9)
    canvas.drawString(inch, A4[1]-50, "Ejemplo de DocTemplate y PageTemplate")
    canvas.restoreState()
    
def pie(canvas,doc):
    canvas.saveState()
    canvas.setFont('Times-Roman',9)
    canvas.drawString(inch, 0.75 * inch, "Page %d" % doc.page)
    canvas.restoreState()

#NIVEL 2: CREAMOS LOS FLOWABLES
#==============================
#Creamos la hoja de Estilo
estilo=getSampleStyleSheet()

#Iniciamos el platypus story
story=[]

#Añadimos al story los flowables. Hay que tener en cuenta que se inicia
#con el primer pageTemplate "UnaColumna"
story.append(Paragraph("Esto es el texto del Frame normal del pagetemplate" +\
                       " de una columna"* 500, estilo['Normal']))
                        
story.append(NextPageTemplate('DosColumnas'))  # Cambio de PageTemplate
story.append(PageBreak())  # Inicio en otra hoja
story.append(Paragraph("Esto es el texto del Frame que pertenece al" +\
                       " pagetemplate de dos columnas" * 500, estilo['Normal']))
                
story.append(NextPageTemplate('UnaColumna'))
story.append(PageBreak())
story.append(Paragraph("Regresamos al texto del Frame normal del" +\
                        " pagetemplate de dos columnas"*100, estilo['Normal']))

#NIVEL 3: CREAMOS LOS FRAMES, para luego asignarlos a un pagetemplate.
#===========================
#Frame (x1, y1, ancho, alto, leftPadding=6, bottomPadding=6, rightPadding=6,
# topPadding=6, id=None, showBoundary=0)

#1. Frame que contendrá a toda el contenido de una hoja
frameN = Frame(inch, inch, 451, 697, id='normal')

#2. Frame de columnas
frame1 = Frame(inch, inch, 220, 697, id='col1')
frame2 = Frame(inch + 230, inch, 220, 697, id='col2')

#NIVEL 4: CREAMOS LOS PAGETEMPLATE, le asignamos los frames y los canvas
#=================================
#PageTemplate(id=None,frames=[],onPage=_doNothing,onPageEnd=_doNothing)
PTUnaColumna = PageTemplate(id='UnaColumna', frames=frameN, onPage=pie)
PTDosColumnas =  PageTemplate(id='DosColumnas', frames=[frame1,frame2],
                        onPage=encabezado, onPageEnd=pie)

#NIVEL 5: CREAMOS EL DOCTEMPLATE, a partir del BaseDocTemplate
#===============================
doc = BaseDocTemplate('test.pdf', pageTemplates=[PTUnaColumna, PTDosColumnas], 
        pagesize=A4)

#Construimos el PDF
doc.build(story)

os.system("test.pdf")
Si han sido observadores, no ha habido un paso directo entre el nivel 1 y el nivel 2, y eso se debe a que los canvas que usamos son NO FLOWABLES, que han sido usados directamente en los pagetemplates del nivel 4. En el siguiente post, veremos como usar canvas en flowables y otras cosas más.

No hay comentarios:

Publicar un comentario