How to set painter of printer correctly?

故事扮演 提交于 2020-08-10 19:17:01

问题


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)

回答1:


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)


来源:https://stackoverflow.com/questions/63156139/how-to-set-painter-of-printer-correctly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!