Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Not able to render a tableview to pdf.



  • hello,
    I am a newbie in qt, and i was trying to render a table view to a pdf using printers. Below is the reduced version of the code and i am not able to achieve it. can someone help me with this. Thanks for any help in advance.

        ui->setupUi(this);
    
        QStandardItemModel *indexPageModel=new QStandardItemModel;
        QTableView *indexPageTableView=new QTableView();
        indexPageTableView->setModel(indexPageModel);
        indexPageTableView->verticalHeader()->setVisible(false);
        indexPageTableView->horizontalHeader()->setVisible(false);
    //populate tableview
    //row1
        QStandardItem *item00 = new QStandardItem("   Title  ");
        item00->setTextAlignment(Qt::AlignCenter);
        indexPageModel->setItem(0, 0, item00);
    
        QStandardItem *item01 = new QStandardItem("  X-axis  ");
        item01->setTextAlignment(Qt::AlignCenter);
        indexPageModel->setItem(0, 1, item01);
    
        QStandardItem *item02 = new QStandardItem("  Y-axis  ");
        item02->setTextAlignment(Qt::AlignCenter);
        indexPageModel->setItem(0, 2, item02);
    
        QStandardItem *item03 = new QStandardItem("    Page#    ");
        item03->setTextAlignment(Qt::AlignCenter);
        indexPageModel->setItem(0, 3, item03);
    
        QStandardItem *item04 = new QStandardItem("    Trend#    ");
        item04->setTextAlignment(Qt::AlignCenter);
        indexPageModel->setItem(0, 4, item04);
    
        QStandardItem *item05 = new QStandardItem("Trend Relationship");
        item05->setTextAlignment(Qt::AlignCenter);
        indexPageModel->setItem(0, 5, item05);
    
        indexPageTableView->resizeColumnsToContents();
    
        QGraphicsScene *scene=new QGraphicsScene(this);
        QGraphicsProxyWidget *proxy = scene->addWidget(indexPageTableView);
        ui->graphicsView->setScene(scene);
        ui->graphicsView->setAlignment(Qt::AlignTop | Qt::AlignLeft);
    
    
        int width = (indexPageModel->columnCount() - 1) + indexPageTableView->verticalHeader()->width();
             for (int column = 0; column < indexPageModel->columnCount(); column++)
                 width = width + indexPageTableView->columnWidth(column);
       indexPageTableView->setMinimumWidth(width);
    //tableview populated
    
    //render tablview to a pdf
       QFileDialog dialog(this);
       dialog.setDefaultSuffix("pdf");
       QString pdffileName = dialog.getSaveFileName(this, tr("Save File"),
                                                  "doc.pdf",
                                                  tr("file(.pdf)"));
    
       QPixmap pixIndexPage(indexPageTableView->size());
       pixIndexPage.fill(Qt::transparent);
       QPainter painterIndexPage(&pixIndexPage);
       painterIndexPage.setRenderHints(QPainter::LosslessImageRendering,QPainter::HighQualityAntialiasing);
       indexPageTableView->render(&painterIndexPage);
    
       QPrinter printer;
       printer.setOutputFileName(pdffileName);
       printer.setFullPage(true);
       printer.setPageSize(QPageSize(QPageSize::A4));
       printer.newPage();
       QPainter painter( &printer);
    
       const QRectF textRect(0, 0, printer.pageRect().width() ,printer.pageRect().height() );
       painter.setClipRect(textRect);
       painter.drawPixmap(textRect,pixIndexPage,QRect(0,0,pixIndexPage.size().width(),pixIndexPage.size().height()));```

  • Lifetime Qt Champion

    @sachinrd
    That is really .. not so pretty :)
    can you try this ?

    void MainWindow::PrintWidget(QWidget* widget) {
    
      QPixmap pix(widget->size());
      QPainter painter(&pix);
      widget->render(&painter);
      painter.end();
      QPrinter printer(QPrinter::HighResolution);
      printer.setPageOrientation(QPageLayout::Orientation::Landscape);
      printer.setOutputFormat(QPrinter::PdfFormat);
      printer.setPaperSize(QPrinter::A4);
      printer.setOutputFileName("test.pdf"); // will be in build folder
    
      painter.begin(&printer);  
      double xscale = printer.pageRect().width() / double(pix.width());
      double yscale = printer.pageRect().height() / double(pix.height());
      double scale = qMin(xscale, yscale);
      painter.translate(printer.paperRect().x() + printer.pageRect().width() / 2,
                        printer.paperRect().y() + printer.pageRect().height() / 2);
      painter.scale(scale, scale);
      painter.translate(-widget->width() / 2, -widget->height() / 2);
      painter.drawPixmap(0, 0, pix);
    
      painter.end();
    }
    

    PrintWidget(ui->tableView);

    and see if that looks better ?

    alt text



  • Managing paging manually is painful, you can use QTextDocument to do it for you:

    QFileDialog dialog(this);
    dialog.setDefaultSuffix("pdf");
    const QString pdffileName = dialog.getSaveFileName(this, tr("Save File"), tr("doc.pdf"), tr("file(.pdf)"));
    if(pdffileName.isEmpty())
        return;
    QTextDocument doc;
    QTextCursor cursor(doc);
    const int rowC = indexPageModel->rowCount();
    const int colC = indexPageModel->columnCount();
    cursor.insertTable(rowC ,colC);
    for(int i=0;i<rowC ;++i){
        for(int j=0;j<colC ;++j){
            cursor.insertText(indexPageModel->index(i,j).data().toString());
            cursor.movePosition(QTextCursor::NextCell);
        }
    }
    QPrinter printer;
    printer.setOutputFileName(pdffileName);
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setPageSize(QPageSize(QPageSize::A4));
    doc.print(&printer);
    

    P.S.
    I think you are leaking the model. change it to QStandardItemModel *indexPageModel=new QStandardItemModel(this);



  • @sachinrd
    @VRonin's suggestion of going via QTextDocument is much easier/more robust. But be aware this will produce a table in PDF with the textual content from the model; it will not necessarily look like what you see in the QTableView (e.g. column widths, coloring, style, etc.). So long as that is acceptable to you.



  • @sachinrd Hi,
    I'd also advise you to switch to QPdfWriter if your intention is to only write PDF files. Makes life easier.



  • @VRonin said in Not able to render a tableview to pdf.:

    QFileDialog dialog(this);
    dialog.setDefaultSuffix("pdf");
    const QString pdffileName = dialog.getSaveFileName(this, tr("Save File"), tr("doc.pdf"), tr("file(.pdf)"));
    if(pdffileName.isEmpty())
    return;
    QTextDocument doc;
    QTextCursor cursor(doc);
    const int rowC = indexPageModel->rowCount();
    const int colC = indexPageModel->columnCount();
    cursor.insertTable(rowC ,colC);
    for(int i=0;i<rowC ;++i){
    for(int j=0;j<colC ;++j){
    cursor.insertText(indexPageModel->index(i,j).data().toString());
    cursor.movePosition(QTextCursor::NextCell);
    }
    }
    QPrinter printer;
    printer.setOutputFileName(pdffileName);
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setPageSize(QPageSize(QPageSize::A4));
    doc.print(&printer);

    Thanks for the reply @VRonin . I tried this solution.. But i want to add a header and footer to the page.. Finding it tough to add it with this approach. And i also have one column with a checkbox widget. rendering that with this approach would be tough right..



  • @JonB yes, i do want to render it as it looks in the QTableView. Is there an easy way to do this. I am able to render it to a pixmap and then paint it to printer object using a painter.
    Something like this:
    painter->drawPixmap(textRect,pix,QRect(0,0,pix.size().width(),pix.size().height()));
    But The content is appearing a bit bigger . Screenshot 2021-05-31 at 5.20.10 PM.png


  • Lifetime Qt Champion

    @sachinrd
    That is really .. not so pretty :)
    can you try this ?

    void MainWindow::PrintWidget(QWidget* widget) {
    
      QPixmap pix(widget->size());
      QPainter painter(&pix);
      widget->render(&painter);
      painter.end();
      QPrinter printer(QPrinter::HighResolution);
      printer.setPageOrientation(QPageLayout::Orientation::Landscape);
      printer.setOutputFormat(QPrinter::PdfFormat);
      printer.setPaperSize(QPrinter::A4);
      printer.setOutputFileName("test.pdf"); // will be in build folder
    
      painter.begin(&printer);  
      double xscale = printer.pageRect().width() / double(pix.width());
      double yscale = printer.pageRect().height() / double(pix.height());
      double scale = qMin(xscale, yscale);
      painter.translate(printer.paperRect().x() + printer.pageRect().width() / 2,
                        printer.paperRect().y() + printer.pageRect().height() / 2);
      painter.scale(scale, scale);
      painter.translate(-widget->width() / 2, -widget->height() / 2);
      painter.drawPixmap(0, 0, pix);
    
      painter.end();
    }
    

    PrintWidget(ui->tableView);

    and see if that looks better ?

    alt text



  • @mrjj said in Not able to render a tableview to pdf.:

    PrintWidget(ui->tableView);

    Thanks for the reply @mrjj . This is working perfect for me. Thanks a lot for the help !!


  • Lifetime Qt Champion

    @sachinrd
    You are welcome.
    Do notice this way of printing it only works when it
    can fit on one page. if it has many rows, it will not be optimal :)