I'm printing a set of tables, each table should get its own page and could be long. The basics are working, but I don't get the footer painted. The problem is the footer will be painted in an extra document(s).
According to the docs I must set the painter to the device. The device is painter, that's correct, but how do I set the painter to the correct Block? Or is it wrong to act this way?
The goal is to use this document twice. 1st attempt is to print, the second a QTextDocument
where I can pic up the QTextTable
's and to compile it with another document elements.
Working example
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtPrintSupport import *
content = [['section 1', [1,2,3,4]],['section2', [5,6,7,8]]]
app = QApplication(sys.argv)
document = QTextDocument ()
printer = QPrinter()
painter = QPainter(printer)
pageRect = printer.pageRect ()
tableFormat = QTextTableFormat ()
cellBlockFormat = QTextBlockFormat ()
cellCharFormat = QTextCharFormat ()
cellCharFormat.setFont (QFont ("Arial", 10))
for rownr, line in enumerate(content):
cursor = QTextCursor (document)
mainFrame = cursor.currentFrame ()
# header
cursor.setPosition (mainFrame.firstPosition ())
cursor.insertHtml ("This is the table for %s"%line[0])
# table
table = cursor.insertTable (3, 4, tableFormat)
for colnr, col in enumerate(line[1]):
print("col:", col)
cellCursor = table.cellAt (rownr + 1, colnr).firstCursorPosition ()
cellCursor.setBlockFormat (cellBlockFormat)
cellCursor.insertText (str (col))
#footer
painter.begin(printer)
painter.drawText (0, pageRect.bottom(), "I may be the footer")
painter.end()
# section finished
cursor.setPosition (mainFrame.lastPosition ())
tableFormat.setPageBreakPolicy (QTextFormat.PageBreak_AlwaysAfter)
cursor.insertBlock (cellBlockFormat, cellCharFormat)
document.print_(printer)
Premise: this is more a hack than a solution, as it's a dirty workaround.
The idea is to subclass QPrinter, override the newPage
method and draw the footer accordingly. This requires that the printer
instance is manually updated with footers.
Unfortunately, there's another important catch: I've not been able to print the footer as long as there's only one page.
In the next days I'll try to look into it again, and find if there's a solution for it.
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtPrintSupport import *
class FooterPrinter(QPrinter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.footers = {}
def paintEngine(self, *args):
engine = super().paintEngine(*args)
self.currentPage = 0
return engine
def drawFooter(self):
text = self.footers.get(self.currentPage)
if not text:
return
painter = super().paintEngine().painter()
dpiy = painter.device().logicalDpiY()
margin = dpiy * (2/2.54)
rect = QRectF(margin, margin, self.width() - margin * 2, self.height() - margin * 2)
fm = QFontMetrics(painter.font(), painter.device())
size = fm.size(0, text)
painter.drawText(rect.left(), rect.bottom() - size.height(),
size.width(), size.height(), Qt.AlignLeft|Qt.AlignTop, text)
def newPage(self):
self.drawFooter()
newPage = super().newPage()
if newPage:
self.currentPage += 1
self.drawFooter()
return newPage
content = [['section 1', [1,2,3,4]],['section2', [5,6,7,8]]]
app = QApplication(sys.argv)
document = QTextDocument()
printer = FooterPrinter()
printer.setOutputFileName('/tmp/test.pdf')
pageRect = printer.pageRect ()
tableFormat = QTextTableFormat ()
cellBlockFormat = QTextBlockFormat ()
cellCharFormat = QTextCharFormat ()
cellCharFormat.setFont (QFont ("Arial", 10))
for rownr, line in enumerate(content):
cursor = QTextCursor (document)
mainFrame = cursor.currentFrame ()
# header
cursor.setPosition (mainFrame.firstPosition ())
cursor.insertHtml ("This is the table for %s"%line[0])
# table
table = cursor.insertTable (3, 4, tableFormat)
for colnr, col in enumerate(line[1]):
cellCursor = table.cellAt (rownr + 1, colnr).firstCursorPosition ()
cellCursor.setBlockFormat (cellBlockFormat)
cellCursor.insertText (str (col))
cursor.setPosition (mainFrame.lastPosition ())
tableFormat.setPageBreakPolicy (QTextFormat.PageBreak_AlwaysAfter)
cursor.insertBlock (cellBlockFormat, cellCharFormat)
printer.footers[rownr] = 'Note for page {}: some text.\nNew line\nAnother new line'.format(rownr + 1)
document.print_(printer)