Search code examples
qtqgraphicsviewqgraphicsitemqgraphicssceneqprinter

Printing QGraphicsScene cuts objects in half


I want to print everything what's on QGraphicsScene:

void MainWindow::on_print_clicked()
{
    if (template_ptr != Q_NULLPTR) {
        QPrinter printer(QPrinter::HighResolution);
        if (QPrintDialog(&printer, this).exec() == QDialog::Accepted) {
            if (QPageSetupDialog(&printer, this).exec() == QDialog::Accepted) {
                QPainter painter(&printer);
                painter.setRenderHint(QPainter::Antialiasing);
                painter.setRenderHint(QPainter::TextAntialiasing);
                qreal x, _y, h, w, fake;
                ui->graphicsView->sceneRect().getRect(&x, &_y, &w, &fake);
                h = template_ptr->page_height*2.0;
                qint32 page = 0;
                while (true) {
                    qreal y = _y + h*page;
                    QRectF leftRect(x, y, w, template_ptr->page_height*2.0*template_ptr->max_pages - h*page);
                    if (ui->graphicsView->scene()->items(leftRect).length() <= 0) {
                        break;
                    }
                    QRectF sourceRect(x, y, w, h);
                    ui->graphicsView->scene()->render(&painter, printer.pageRect(), sourceRect);
                    printer.newPage();
                    page++;
                }
            }
        }
    }
}

That's the effect (PDF file): Problem with printing

Every point on the lists is a single QGraphicsItem and I don't know what's the easiest way to move the items that doesn't fit within a page, to the next page... I probably could do some error-prone mathematics to achieve that but I'm pretty sure this can be resolved in some elegant way.


Solution

  • What I would do...

    Step 1: I would first create a copy of the scene (a new QGraphicsScene with the same size as your original) and move all items there.

    Step 2: Create a temporary scene for each new page, with a sceneRect equal to the section you wish to print.

    Step 3: Move to it the items from the scene copy, that are contained in the sceneRect of the temp scene.

    Step 4: After printing, move the printed items to the original scene...

    Step 5: Shorten your copy scene bounding rect to the bounding rect of the items still left inside it. (to allow step 4 to place items exactly in place, change the x/y coordinates as well as change the w/h)

    Repeat steps 3 to 5 till the copy scene is empty.