Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reportlab: header with data from page

I'm using the on page function and a page template to make headers for a subset of the pages in my document:

templates.append(PageTemplate(id='Overview', frames=frame, onPage=HeaderOverview))

The header function for this template:

################################
# Function HeaderOverview - header for overview page
def HeaderOverview(canvas,doc):
    canvas.saveState()
    headboxh = 15
    headboxx = 20
    headboxy = 730
    headboxw = 570
    canvas.rect(headboxx, headboxy, headboxw, headboxh, fill=1)  
    canvas.setFillColor(colors.black)
    canvas.setFont("Helvetica", 14)
    canvas.setFillColor(colors.white)

    canvas.drawString(headboxx + 15,headboxy+.25*headboxh,"Mathematics")
    textWidth = stringWidth("Mathematics", "Helvetica", 12) 
    canvas.setFont("Helvetica", 12)
    canvas.drawString(headboxw - 15 - textWidth,headboxy+.25*headboxh,course)

    canvas.restoreState()

This works great, except that the course variable that's passed (which changes with each page in the section) is the last one in the sequence, since this function's not really called until the final build (I think that's how it works). What I need is to do this so that the value is the value that's on the page. If I could draw it as I write the page itself, that'd be fine, too. Here's my attempt at that:

####################################################################################
# Function makeGradeOverview(course): makes Overview chart for grade
#
def makeGradeOverview(canvas, course):
    report.append(NextPageTemplate("Overview"))
    report.append(PageBreak())

    headboxh = 50
    headboxx = 20
    headboxy = 600#730
    headboxw = 540

    canvas.saveState()
    canvas.setFont("Helvetica", 12)
    textWidth = stringWidth(course, "Helvetica", 12)
    canvas.drawString(headboxw - 15 - textWidth,headboxy+.25*headboxh,course)
    canvas.restoreState()
    # put course name as title
    if len(course)<=2:
        headerrow = ''.join(['Grade ', course, ' Overview'])
    else:
        headerrow = ''.join([course, ' Overview'])
    report.append(Paragraph(headerrow, styles["Overview Title"]))

    report.append(Spacer(1, 16))

    GridInfo = []
    topics = topiclist(course)

    for topic in topics:
        report.append(Paragraph(topic, styles["Overview Sub"]))
        report.append(Spacer(1, 8))

        subtopics = subtopiclist(course, topic)

        sublist = []
        for subtopic in subtopics:
             report.append(Paragraph(''.join([r'<bullet>&bull</bullet>',subtopic]), styles["Overview Table"]))

This doesn't throw an error or anything, but it doesn't seem to actually draw anything, either.

Thanks for the help!

like image 929
DeltaG Avatar asked Feb 16 '13 17:02

DeltaG


1 Answers

Here's another idea...

Perhaps it would work to use specific flowables that can be identified to update the course. You can add custom attributes to flowables if necessary to help identify them (see this post).

For example, you might be able to do something like this:

...
report.append(some_content)

report.append(PageBreak())
report[-1].new_course = True  # gives that PageBreak flowable a custom attribute

report.append(some_more_content)
...

And set up some variables:

course_list = [...]
course_iter = iter(course_list)
current_course = next(course_iter)

Then you can check each flowable after it is rendered to see if it has that attribute and update the current course if it does.

def afterFlowable(flowable):
    global current_course
    if hasattr(flowable, 'new_course'):
        current_course = next(course_iter)

doc.afterFlowable = afterFlowable

HeaderOverview will be able to use the current_course variable to get the right course, since both HeaderOverview and afterFlowable are called at various points during the final build.

like image 58
grc Avatar answered Oct 22 '22 20:10

grc