Распечатать элементы в PDF - PullRequest
       0

Распечатать элементы в PDF

1 голос
/ 22 февраля 2020

У меня есть окно с 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()

nameItem на j - это метка имени строки, m_items [4] - это метка имени для каждого круга.

Моя проблема в том, что я не могу получить точную высоту отрисованной сцены, более того, я не знаю, как можно переполнить текст до на следующей странице, если содержимое не помещается в одну.

было бы замечательно, если бы я мог каким-то образом визуализировать каждую строку и соответствующие ей кружки отдельно для каждого соединения, сохраненные в lineList

примечание: строка ребенок каждого круга, а имена каждой строки и круга - их дети, реализованные во многом таким же образом, как и ответ на мой предыдущий вопрос , где лежит мой последний вопрос о предметах захвата, также являющихся отрендерено issues Issues

  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_())

, если возможно, возможность печатать, тестировать, затем кружить для всех кругов была бы для меня достаточно приличной.

Неправильный пример вывода:

enter image description here

1 Ответ

3 голосов
/ 23 февраля 2020

Чтобы понять, что такое рисование, вы должны понять, как работает метод QGraphicsScene::render():

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

Визуализирует исходный прямоугольник из сцены в цель, используя художник. Эта функция полезна для захвата содержимого сцены на устройство рисования, такое как QImage (например, чтобы сделать снимок экрана), или для печати с помощью QPrinter. Например:

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

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

Если source является нулевым прямоугольником, эта функция будет использовать sceneRect (), чтобы определить, что визуализировать. Если target является нулевым прямоугольником, будут использоваться размеры устройства рисования художника.

Исходное содержимое прямоугольника будет преобразовано в соответствии с aspectRatioMode для соответствия целевому прямоугольнику. По умолчанию соотношение сторон сохраняется, а источник масштабируется для соответствия цели.

См. Также 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_())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...