【问题标题】:Combining QPainter and QTextDocument on QPdfWriter在 QPdfWriter 上结合 QPainter 和 QTextDocument
【发布时间】:2021-10-17 22:05:41
【问题描述】:

在另一个问题中,我了解到QTextDocumentwas told,您可以在 PDF 的同一页面上使用 QPainterQTextDocument。但是,当我尝试这样做时,他们都重新启动了文档,清除了对方的内容。

from PySide6.QtGui import QPdfWriter, QPainter, QPageSize, QTextDocument, Qt
from PySide6.QtWidgets import QApplication


def main():
    app = QApplication()
    pdf = QPdfWriter('example.pdf')
    pdf.setPageSize(QPageSize.Letter)

    # Whichever of these goes second, overwrites the first.
    draw_diagram(pdf)
    print_document(pdf)

    app.exit(0)


def draw_diagram(pdf: QPdfWriter):
    painter = QPainter(pdf)
    painter.drawArc(painter.window().width()//4,
                    painter.window().height()//2 - painter.window().width()//4,
                    painter.window().width()//2,
                    painter.window().width()//2,
                    0,
                    5760)
    painter.drawText(0,
                     painter.window().height()//2,
                     painter.window().width(),
                     painter.window().height()//10,
                     Qt.AlignHCenter | Qt.AlignTop,
                     'https://donkirkby.github.io')
    print(pdf.newPage())
    painter.drawText(painter.window().width()//2,
                     painter.window().height()//2,
                     'Bar')
    print(pdf.newPage())
    painter.end()


def print_document(pdf: QPdfWriter):
    html = "<a href='https://donkirkby.github.io'>donkirkby.github.io</a>"

    document = QTextDocument()
    document.setHtml(html)
    document.print_(pdf)


main()

理想情况下,我希望文本和绘图在同一页面上,但此代码试图将它们分开,以免它们相互覆盖。这两种方法都不起作用。

如何将绘图与文本文档结合起来? QTextCursor 有用吗?

【问题讨论】:

    标签: python qpainter pyside6 qtextdocument


    【解决方案1】:

    问题是每次设置 QPainter 时都会重置 QPdfWriter。一个可能的解决方案是使用相同的 QPainter,而不是使用 drawContents 的打印方法,您还必须手动处理分页。

    from PySide6.QtGui import QPdfWriter, QPainter, QPageSize, QTextDocument, Qt
    from PySide6.QtWidgets import QApplication
    
    
    def main():
        app = QApplication()
        pdf = QPdfWriter("example.pdf")
        pdf.setPageSize(QPageSize.Letter)
    
        painter = QPainter(pdf)
    
        draw_diagram(painter, pdf)
        print_document(painter, pdf)
    
        painter.end()
    
    
    def draw_diagram(painter: QPainter, pdf: QPdfWriter):
        painter.drawArc(
            painter.window().width() // 4,
            painter.window().height() // 2 - painter.window().width() // 4,
            painter.window().width() // 2,
            painter.window().width() // 2,
            0,
            5760,
        )
        painter.drawText(
            0,
            painter.window().height() // 2,
            painter.window().width(),
            painter.window().height() // 10,
            Qt.AlignHCenter | Qt.AlignTop,
            "https://donkirkby.github.io",
        )
        print(pdf.newPage())
        painter.drawText(
            painter.window().width() // 2, painter.window().height() // 2, "Bar"
        )
        print(pdf.newPage())
    
    
    def print_document(painter: QPainter, pdf: QPdfWriter):
        document = QTextDocument()
        document.documentLayout().setPaintDevice(pdf)
    
        html = "<a href='https://donkirkby.github.io'>donkirkby.github.io</a>"
        document.setHtml(html)
    
        document.drawContents(painter)
    
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

      【解决方案2】:

      虽然我最终使用了从document.print_() 切换到document.drawContents()eyllanesc's answer,但我也尝试了QTextCursorQPyTextObject。这个TextObject example 给出了很好的介绍。我认为,如果我需要分布在多个页面上,这将很有用。

      这是我转换为使用QPyTextObject的问题的示例:

      from PySide6.QtCore import QSizeF, QRectF
      from PySide6.QtGui import (QPdfWriter, QPainter, QPageSize, QTextDocument, Qt, QPyTextObject, QTextFormat, QTextCursor,
                                 QTextCharFormat)
      from PySide6.QtWidgets import QApplication
      
      DIAGRAM_TEXT_FORMAT = QTextFormat.UserObject + 1
      DIAGRAM_DATA = 1
      OBJECT_REPLACEMENT = chr(0xfffc)
      
      
      def main():
          app = QApplication()
          pdf = QPdfWriter('example.pdf')
          pdf.setPageSize(QPageSize.Letter)
      
          print_document(pdf)
      
          app.exit(0)
      
      
      class Diagram(QPyTextObject):
          def __init__(self, parent=None):
              super().__init__(parent)
      
          # noinspection PyPep8Naming,PyShadowingBuiltins
          def intrinsicSize(self,
                            doc: QTextDocument,
                            posInDocument: int,
                            format: QTextFormat) -> QSizeF:
              diameter = doc.textWidth()/4
              return QSizeF(doc.textWidth(), diameter)
      
          # noinspection PyPep8Naming,PyShadowingBuiltins
          def drawObject(self,
                         painter: QPainter,
                         rect: QRectF,
                         doc: QTextDocument,
                         posInDocument: int,
                         format: QTextFormat):
              diameter = rect.height()
              message = format.property(DIAGRAM_DATA)
              painter.drawArc((rect.width() - diameter) // 2,
                              rect.y(),
                              diameter,
                              diameter,
                              0,
                              5760)
              painter.drawText(rect,
                               Qt.AlignHCenter | Qt.AlignVCenter,
                               message)
      
      
      def print_document(pdf: QPdfWriter):
          html = """\
      <h1>Title</h1>
      <p>Lorem ipsum
      <a href='https://donkirkby.github.io'>donkirkby.github.io</a>
      dolores sit amet.</p>
      """
      
          document = QTextDocument()
          document.setPageSize(QSizeF(pdf.width(), pdf.height()))
          font = document.defaultFont()
          font.setPixelSize(pdf.height()//60)
          document.setDefaultFont(font)
          diagram_handler = Diagram()
          doc_layout = document.documentLayout()
          doc_layout.registerHandler(DIAGRAM_TEXT_FORMAT, diagram_handler)
      
          document.setHtml(html)
          cursor = QTextCursor(document)
          cursor.movePosition(cursor.End)
          cursor.insertText('\n')
          
          diagram_format = QTextCharFormat()
          diagram_format.setObjectType(DIAGRAM_TEXT_FORMAT)
      
          for i in range(1, 11):
              cursor.insertHtml(f'<h3>Heading {i}</h3>')
              cursor.insertText('\n')
              diagram_format.setProperty(DIAGRAM_DATA, f'Message {i} in a circle')
              cursor.insertText(OBJECT_REPLACEMENT, diagram_format)
      
          document.print_(pdf)
      
      
      main()
      

      我仍然不喜欢这种方法的一点是,可以在标题和图表之间添加分页符。我会问一个关于这个的后续问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-08
        • 2020-07-16
        • 2020-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-15
        相关资源
        最近更新 更多