将项目打印为pdf

布莱恩

我有一个带有QGraphicsScene作为画家的窗口,我想在按下按钮时将其元素呈现为pdf文件。

def generateReport(self):
        lineList = {}
        for i in self.circleList:
            for j,k in i.lineItems:
                if j not in lineList:
                    lineList[j] = [i, k]
        printed = QPdfWriter("Output.pdf")
        printed.setPageSize(QPagedPaintDevice.A4)
        printer = QPainter(printed)
        self.painter.render(printer)
        for i,j in enumerate(lineList):
            # j.scene().render(printer)
            # lineList[j][0].scene().render(printer)
            # lineList[j][1].scene().render(printer)
            printer.drawText(0, self.painter.height() + i*200, f'{j.nameItem.toPlainText()}: {lineList[j][0].m_items[4].toPlainText()}, {lineList[j][1].m_items[4].toPlainText()}')
        printer.end()

j上的nameItem是该行的名称标签,m_items [4]是每个圆的名称标签。

我的问题是,我似乎无法获得渲染场景的确切高度,此外,如果内容不适合我如何将文字溢出到下一页,我零线索。

如果我能以某种方式为每个连接分别渲染每一行及其对应的圆,将很可爱,存储在lineList中

注意:该线是每个圆圈的子代,每个线和圆圈的名称都是其子代的名称,其实现方式与我上一个问题的答案大致相同,其中我的最后一个抓握项也位于其中。

我发现我可以创建一个新场景,将每个项目一个接一个地移动并将其渲染为pdf,但这会引发两个独立的问题

  1. 我无法添加换行符,并避免在前一个渲染图上过度绘制新渲染图,并且
  2. 我无法定位文本,因为addText不接受位置参数。

MRE:

import random
from fbs_runtime.application_context.PyQt5 import ApplicationContext
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter, QPdfWriter, QBrush, QPagedPaintDevice
from PyQt5.QtWidgets import (QDialog, QGraphicsScene,
                             QGraphicsView, QGridLayout,
                             QPushButton, QGraphicsEllipseItem)

class gui(QDialog):
    def __init__(self, parent=None):
        super(gui, self).__init__(parent)
        self.resize(1280, 720)
        self.painter = QGraphicsScene(0, 0, self.width() - 50, self.height() - 70)
        self.painter.setBackgroundBrush(QBrush(Qt.white))
        self.canvas = QGraphicsView(self.painter)
        mainLayout = QGridLayout()
        mainLayout.addWidget(self.canvas, 0, 0, -1, -1)
        self.setLayout(mainLayout)

    @property
    def circleList(self):
        return [item for item in self.painter.items() if isinstance(item, QGraphicsEllipseItem)]

    def newCircle(self):
        self.painter.addEllipse( random.randint(100, 400), random.randint(100, 400), 50 + random.random() * 200, 50 + random.random() * 200)

    def generateReport(self):
        printed = QPdfWriter("Output.pdf")
        printed.setPageSize(QPagedPaintDevice.A4)
        printer = QPainter(printed)
        self.painter.render(printer)
        for i,j in enumerate(self.circleList):
            printer.drawText(0, printer.viewport().height() + i*200, 'test')
        printer.end()


if __name__ == "__main__":
    app = ApplicationContext()
    test = gui()
    test.newCircle()
    test.newCircle()
    test.newCircle()
    test.generateReport()
    test.show()
    exit(app.app.exec_())

如果可能的话,对所有圈子来说,打印,测试然后圈子的能力对我来说已经足够了。

错误的输出示例:

在此处输入图片说明

永乐

要了解绘画是什么样的,您必须了解QGraphicsScene::render()方法的工作原理:

void QGraphicsScene::render(QPainter *painter, const QRectF &target = QRectF(), const QRectF &source = QRectF(), Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio)

Renders the source rect from scene into target, using painter. This function is useful for capturing the contents of the scene onto a paint device, such as a QImage (e.g., to take a screenshot), or for printing with QPrinter. For example:

QGraphicsScene scene;
scene.addItem(...
...
QPrinter printer(QPrinter::HighResolution);
printer.setPaperSize(QPrinter::A4);

QPainter painter(&printer);
scene.render(&painter);

If source is a null rect, this function will use sceneRect() to determine what to render. If target is a null rect, the dimensions of painter's paint device will be used.

The source rect contents will be transformed according to aspectRatioMode to fit into the target rect. By default, the aspect ratio is kept, and source is scaled to fit in target.

See also QGraphicsView::render().

在您的情况下,如果未传递源,则将复制整个sceneRect(0、0、1230、650)并将其绘制在pdf页面上,如果大小不匹配,则将缩放大小。因此,从上面可以看出,如果要打印项目,则必须将其在场景中占据的空间作为源传递,并隐藏其他项目,而目标是要绘制的位置,这涉及到计算新的根据上一个项目的打印位置。

考虑到上述情况,可能的解决方法如下:

import random

from PyQt5 import QtCore, QtGui, QtWidgets


class Gui(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(Gui, self).__init__(parent)
        self.resize(1280, 720)
        self.scene = QtWidgets.QGraphicsScene(
            0, 0, self.width() - 50, self.height() - 70
        )
        self.scene.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.white))
        self.canvas = QtWidgets.QGraphicsView(self.scene)
        mainLayout = QtWidgets.QGridLayout(self)
        mainLayout.addWidget(self.canvas)

    @property
    def circleList(self):
        return [
            item
            for item in self.scene.items()
            if isinstance(item, QtWidgets.QGraphicsEllipseItem)
        ]

    def newCircle(self):
        self.scene.addEllipse(
            random.randint(100, 400),
            random.randint(100, 400),
            50 + random.random() * 200,
            50 + random.random() * 200,
        )

    def generateReport(self):
        printer = QtGui.QPdfWriter("Output.pdf")
        printer.setPageSize(QtGui.QPagedPaintDevice.A4)
        printer.setResolution(100)
        painter = QtGui.QPainter(printer)
        delta = 20
        f = painter.font()
        f.setPixelSize(delta)
        painter.setFont(f)
        # hide all items
        last_states = []
        for item in self.scene.items():
            last_states.append(item.isVisible())
            item.setVisible(False)

        target = QtCore.QRectF(0, 0, printer.width(), 0)

        for i, item in enumerate(self.circleList):
            item.setVisible(True)
            source = item.mapToScene(item.boundingRect()).boundingRect()
            target.setHeight(source.height())
            if target.bottom() > printer.height():
                printer.newPage()
                target.moveTop(0)
            self.scene.render(painter, target, source)
            f = painter.font()
            f.setPixelSize(delta)
            painter.drawText(
                QtCore.QRectF(
                    target.bottomLeft(), QtCore.QSizeF(printer.width(), delta + 5)
                ),
                "test",
            )
            item.setVisible(False)
            target.setTop(target.bottom() + delta + 20)
        # restore visibility
        for item, state in zip(self.scene.items(), last_states):
            item.setVisible(state)
        painter.end()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Gui()
    for _ in range(200):
        w.newCircle()
    w.generateReport()
    w.show()
    sys.exit(app.exec_())

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

将打印机配置为 Laravel 5.6 项目,生成 PDF 并打印 PDF

来自分类Dev

将QWebView打印为PDF

来自分类Dev

将PDF打印为讲义

来自分类Dev

可以将FullCalendar打印为PDF吗?

来自分类Dev

将python代码打印为PDF

来自分类Dev

通过JavaScript将网页打印为pdf

来自分类Dev

Python将PDF打印为多个图形

来自分类Dev

将网页打印为PDF并保留链接

来自分类Dev

通过JavaScript将网页打印为pdf

来自分类Dev

使用pdfbox将byte []打印为pdf

来自分类Dev

尝试将 ResultSet 打印为 PDF 文件

来自分类Dev

将PDF打印为PDF是否会降低其质量?

来自分类Dev

使用工作超链接将网页“打印”为pdf

来自分类Dev

使用Python 2.76将多个网页打印为PDF

来自分类Dev

Awesomium错误地将页面打印为PDF

来自分类Dev

如何将SWF文件批量打印为PDF?

来自分类Dev

自动将Mathcad工作表打印为PDF

来自分类Dev

如何将大量URL打印为PDF

来自分类Dev

如何将 html 表格打印为 pdf?

来自分类Dev

使用 VBA 将现有宏打印为 PDF

来自分类Dev

使用Ghostscript和.NET将PDF打印为灰度打印机

来自分类Dev

如何将 pdf 文件打印为 pdf,包括注释和从终端强制光栅化

来自分类Dev

CefGlue静默打印为PDF

来自分类Dev

将reddit json解析为Python数组并从数组中打印项目

来自分类Dev

将目录中的每个 PDF 文件另存为另一个 PDF(类似于将 PDF 打印为 PDF 的操作)

来自分类Dev

PyQt将多页打印为PDF仅获得最后一页

来自分类Dev

如何以编程方式将电子邮件打印为pdf

来自分类Dev

Google字体可防止在将Vue应用打印为pdf时选择文本

来自分类Dev

将TeeChart导出为PDF后,打印后在Acrobat Reader中显示错误