如何从 QWebEngineView 打印 [英] How to print from QWebEngineView

查看:95
本文介绍了如何从 QWebEngineView 打印的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从我的应用程序中打印一份报告,其中包括文本和表格.由于 QTextDocument 不够用,我决定使用 QWebEngineView 和 Qt 富文本引擎不支持的更复杂的 HTML/CSS.

I am trying to print a report from within my application, which involves both text and tables. Since QTextDocument won't be sufficient, I've decided to go with QWebEngineView and more sophisticated HTML/CSS which is not supported by the Qt rich text engine.

我可以从视图创建 PDF,但是我有一些普遍的误解,因为有时它会崩溃,并且打印而不是 PDF 创建会崩溃.

I am able to create a PDF from the view, however I am having some general misconceptions, because at times its crashing, and also printing instead of PDF creation crashes.

这是我的尝试:

方法一:创建PDF

这是唯一可行的变体:

    auto webView = new QWebEngineView();
    webView->setHtml(contents);

    const QString fn = QFileDialog::getSaveFileName(0, "Save pdf", ".", "PDF Files (*.pdf)");

    if (!fn.isEmpty())
       webView->page()->printToPdf(fn);

然而,这仅适用于对话框(?!).如果我像这样改变它:

This, however, only works because of the dialog (?!). If I change it like this:

    QString fn ="/Users/s710/Downloads/test.pdf";
    auto webView = new QWebEngineView();
    webView->setHtml(contents);
    webView->page()->printToPdf(fn);

它将创建一个带有空白页的 PDF.所以我猜以上只是偶然的.

It is going to create a PDF with a blank page. So I guess the above only works by accident.

方法二:直接打印

这种方法崩溃了:

    auto webView = new QWebEngineView();
    webView->setHtml(contents);

    QPrinter printer(QPrinter::QPrinter::ScreenResolution);
    printer.setOutputFormat(QPrinter::NativeFormat);
    printer.setPaperSize(QPrinter::A4);
    printer.setPageMargins(12, 16, 12, 20, QPrinter::Millimeter);

    webView->page()->print(&printer, [](bool){});

Crash:
1   QPrinter::pageRect() const                                                                                                                                                                                                                                 (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtPrintSupport.framework/Versions/5/QtPrintSupport                       0x100247fe4    
2   QWebEnginePagePrivate::didPrintPage(unsigned long long, QByteArray const&)                                                                                                                                                                                 (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineWidgets.framework/Versions/5/QtWebEngineWidgets               0x100200f0a    
3   QtWebEngineCore::callbackOnPrintingFinished(QtWebEngineCore::WebContentsAdapterClient *, int, std::vector<char> const&)                                                                                                                                    (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineCore.framework/Versions/5/QtWebEngineCore                     0x100899693    
4   base::debug::TaskAnnotator::RunTask(const char *, base::PendingTask *)                                                                                                                                                                                     (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineCore.framework/Versions/5/QtWebEngineCore                     0x10295d402    
5   base::MessageLoop::RunTask(base::PendingTask *)                                                                                                                                                                                                            (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineCore.framework/Versions/5/QtWebEngineCore                     0x10298395f    
6   base::MessageLoop::DoWork()                                                                                                                                                                                                                                (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineCore.framework/Versions/5/QtWebEngineCore                     0x102983ef9    
7   std::__function::__func<QtWebEngineCore::(anonymous namespace)::MessagePumpForUIQt::MessagePumpForUIQt()::'lambda'(), std::allocator<QtWebEngineCore::(anonymous namespace)::MessagePumpForUIQt::MessagePumpForUIQt()::'lambda'()>, void ()>::operator()() (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineCore.framework/Versions/5/QtWebEngineCore                     0x100839f99    
8   QObject::event(QEvent *)                                                                                                                                                                                                                                   (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtCore.framework/Versions/5/QtCore                                       0x10824bcf6    
...

<小时>

方法三:等待webview加载完成,然后创建PDF

因此,由于似乎与阻止文件对话框有所不同,因此我认为在视图尚未加载 HTML 时可能会出现问题.我还读到 QWebEngineView 资源很重,所以我想我可以等待它完成加载.

So since there seems to be a difference with the blocking file dialog, I thought it might have issues when the view has not yet loaded the HTML. I also read that QWebEngineView is resource heavy, so I thought I could wait for it to finish loading.

然而,这也会崩溃

    auto webView = new QWebEngineView();

    QObject::connect(webView, &QWebEngineView::loadFinished, this, [&webView](bool ok)
    {
        QString fn ="/Users/s710/Downloads/test.pdf";
        webView->page()->printToPdf(fn);
    });

    webView->setHtml(contents);

Crash:
1   QWebEnginePage::printToPdf(QString const&, QPageLayout const&)                                                                                                                                                          (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineWidgets.framework/Versions/5/QtWebEngineWidgets     0x100204cd7    
2   Printer::print(MonthItem *, QWidget *)::$_0::operator()(bool) const                                                                                                                                                     printer.cpp                                                                                            203 0x100016eeb    
3   QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<bool>, void, Printer::print(MonthItem *, QWidget *)::$_0>::call(Printer::print(MonthItem *, QWidget *)::$_0&, void * *)                               qobjectdefs_impl.h                                                                                     146 0x100016dc8    
4   void QtPrivate::Functor<Printer::print(MonthItem *, QWidget *)::$_0, 1>::call<QtPrivate::List<bool>, void>(Printer::print(MonthItem *, QWidget *)::$_0&, void *, void * *)                                              qobjectdefs_impl.h                                                                                     256 0x100016d71    
5   QtPrivate::QFunctorSlotObject<Printer::print(MonthItem *, QWidget *)::$_0, 1, QtPrivate::List<bool>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void * *, bool *)                                        qobjectdefs_impl.h                                                                                     439 0x100016d1d    
6   QMetaObject::activate(QObject *, int, int, void * *)                                                                                                                                                                    (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtCore.framework/Versions/5/QtCore                             0x10825153b    
7   QWebEngineView::loadFinished(bool)                                                                                                                                                                                      (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineWidgets.framework/Versions/5/QtWebEngineWidgets     0x10020cb3f

<小时>

方法四:等待webview加载完毕,然后打印

这也会崩溃:

    auto webView = new QWebEngineView();

    QObject::connect(webView, &QWebEngineView::loadFinished, this, [&webView](bool ok)
    {
        QPrinter printer(QPrinter::PrinterResolution);
        printer.setOutputFormat(QPrinter::NativeFormat);
        printer.setPaperSize(QPrinter::A4);
        printer.setPageMargins(12, 16, 12, 20, QPrinter::Millimeter);

        webView->page()->print(&printer, [](bool){});
    });

    webView->setHtml(contents);

Crash:
1   QWebEngineView::page() const                                                                                                                                                                                            (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineWidgets.framework/Versions/5/QtWebEngineWidgets     0x10020f05d    
2   Printer::print(MonthItem *, QWidget *)::$_0::operator()(bool) const                                                                                                                                                     printer.cpp                                                                                            207 0x100016b35    
3   QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<bool>, void, Printer::print(MonthItem *, QWidget *)::$_0>::call(Printer::print(MonthItem *, QWidget *)::$_0&, void * *)                               qobjectdefs_impl.h                                                                                     146 0x100016a88    
4   void QtPrivate::Functor<Printer::print(MonthItem *, QWidget *)::$_0, 1>::call<QtPrivate::List<bool>, void>(Printer::print(MonthItem *, QWidget *)::$_0&, void *, void * *)                                              qobjectdefs_impl.h                                                                                     256 0x100016a31    
5   QtPrivate::QFunctorSlotObject<Printer::print(MonthItem *, QWidget *)::$_0, 1, QtPrivate::List<bool>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void * *, bool *)                                        qobjectdefs_impl.h                                                                                     439 0x1000169dd    
6   QMetaObject::activate(QObject *, int, int, void * *)                                                                                                                                                                    (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtCore.framework/Versions/5/QtCore                             0x10825353b    
7   QWebEngineView::loadFinished(bool)                                                                                                                                                                                      (x86_64) /Users/s710/Qt/5.12.6/clang_64/lib/QtWebEngineWidgets.framework/Versions/5/QtWebEngineWidgets     0x10020eb3f    

因为到处都是崩溃,所以我觉得很愚蠢,但我不知道哪里出了问题.有人可以指出我使用 QWebEngineView 的工作打印功能吗?

So I feel pretty stupid because of the crashing all over the place, but I don't know what could be wrong. Can someone point me to a working print function using QWebEngineView please?

推荐答案

在第一种方法中,我认为它失败了,因为尚未加载 HTML 或 url 而您想要打印文本,因此可能的解决方案是使用loadFinished 信号开始打印并使用 pdfPrintingFinished 知道打印何时完成.

In the first approach I think it fails because the HTML or url is not loaded yet and you want to print the text, so a possible solution is to use the loadFinished signal to start printing and use pdfPrintingFinished to know when the printing is finished.

#include <QtWebEngineWidgets>

class Widget : public QWidget
{
public:
    explicit Widget(QWidget *parent = nullptr):
        QWidget(parent), button(new QPushButton), progressbar(new QProgressBar), view(new QWebEngineView)
    {
        button->setText(tr("Press me"));
        button->setEnabled(false);

        connect(button, &QPushButton::clicked, this, &Widget::onClicked);
        connect(view, &QWebEngineView::loadFinished, this, &Widget::onLoadFinished);
        connect(view->page(), &QWebEnginePage::pdfPrintingFinished, this, &Widget::onPdfPrintingFinished);

        QString html = R"(<!DOCTYPE html>
                       <html>
                       <head>
                       <style>
                       table {
                       font-family: arial, sans-serif;
                       border-collapse: collapse;
                       width: 100%;
                       }

                       td, th {
                       border: 1px solid #dddddd;
                       text-align: left;
                       padding: 8px;
                       }

                       tr:nth-child(even) {
                       background-color: #dddddd;
                       }
                       </style>
                       </head>
                       <body>

                       <h2>HTML Table</h2>

                       <table>
                       <tr>
                       <th>Company</th>
                       <th>Contact</th>
                       <th>Country</th>
                       </tr>
                       <tr>
                       <td>Alfreds Futterkiste</td>
                       <td>Maria Anders</td>
                       <td>Germany</td>
                       </tr>
                       <tr>
                       <td>Centro comercial Moctezuma</td>
                       <td>Francisco Chang</td>
                       <td>Mexico</td>
                       </tr>
                       <tr>
                       <td>Ernst Handel</td>
                       <td>Roland Mendel</td>
                       <td>Austria</td>
                       </tr>
                       <tr>
                       <td>Island Trading</td>
                       <td>Helen Bennett</td>
                       <td>UK</td>
                       </tr>
                       <tr>
                       <td>Laughing Bacchus Winecellars</td>
                       <td>Yoshi Tannamuri</td>
                       <td>Canada</td>
                       </tr>
                       <tr>
                       <td>Magazzini Alimentari Riuniti</td>
                       <td>Giovanni Rovelli</td>
                       <td>Italy</td>
                       </tr>
                       </table>

                       </body>
                       </html>
                       )";

        view->setHtml(html);
        auto lay = new QVBoxLayout(this);
        lay->addWidget(button);
        lay->addWidget(progressbar);
        lay->addWidget(view);
        resize(640, 480);
    }
private:
    void onLoadFinished(bool ok){
        button->setEnabled(ok);
    }
    void onClicked(){
        progressbar->setRange(0, 0);
        QString fn = "/Users/s710/Downloads/test.pdf";
        view->page()->printToPdf(fn);
    }
    void onPdfPrintingFinished(const QString & filename, bool ok){
        qDebug() << filename << ok;
        progressbar->setRange(0, 1);
    }
private:
    QPushButton *button;
    QProgressBar *progressbar;
    QWebEngineView *view;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

在您使用 QPrinter 的情况下,我认为导致错误的原因是 QPrinter 是一个局部变量,该变量在函数执行完成时被消除,但 Qt 尝试异步访问该变量但该对象不存在.解决方案是扩展QPrinter的范围.

In the case where you use QPrinter I think that the error is caused because QPrinter is a local variable that is eliminated when the function is finished executing but Qt tries to access that variable asynchronously but the object does not exist. The solution is to extend the scope of QPrinter.

#include <QtWebEngineWidgets>

class Widget : public QWidget
{
public:
    Widget(QWidget *parent = nullptr):
        QWidget(parent), button(new QPushButton), progressbar(new QProgressBar), view(new QWebEngineView)
    {
        button->setText(tr("Press me"));
        button->setEnabled(false);

        connect(button, &QPushButton::clicked, this, &Widget::onClicked);
        connect(view, &QWebEngineView::loadFinished, this, &Widget::onLoadFinished);

        printer.setResolution(QPrinter::PrinterResolution);
        printer.setOutputFormat(QPrinter::NativeFormat);
        printer.setPaperSize(QPrinter::A4);
        printer.setPageMargins(12, 16, 12, 20, QPrinter::Millimeter);
        QString html = R"(<!DOCTYPE html>
                       <html>
                       <head>
                       <style>
                       table {
                       font-family: arial, sans-serif;
                       border-collapse: collapse;
                       width: 100%;
                       }

                       td, th {
                       border: 1px solid #dddddd;
                       text-align: left;
                       padding: 8px;
                       }

                       tr:nth-child(even) {
                       background-color: #dddddd;
                       }
                       </style>
                       </head>
                       <body>

                       <h2>HTML Table</h2>

                       <table>
                       <tr>
                       <th>Company</th>
                       <th>Contact</th>
                       <th>Country</th>
                       </tr>
                       <tr>
                       <td>Alfreds Futterkiste</td>
                       <td>Maria Anders</td>
                       <td>Germany</td>
                       </tr>
                       <tr>
                       <td>Centro comercial Moctezuma</td>
                       <td>Francisco Chang</td>
                       <td>Mexico</td>
                       </tr>
                       <tr>
                       <td>Ernst Handel</td>
                       <td>Roland Mendel</td>
                       <td>Austria</td>
                       </tr>
                       <tr>
                       <td>Island Trading</td>
                       <td>Helen Bennett</td>
                       <td>UK</td>
                       </tr>
                       <tr>
                       <td>Laughing Bacchus Winecellars</td>
                       <td>Yoshi Tannamuri</td>
                       <td>Canada</td>
                       </tr>
                       <tr>
                       <td>Magazzini Alimentari Riuniti</td>
                       <td>Giovanni Rovelli</td>
                       <td>Italy</td>
                       </tr>
                       </table>

                       </body>
                       </html>
                       )";

        view->setHtml(html);

        auto lay = new QVBoxLayout(this);
        lay->addWidget(button);
        lay->addWidget(progressbar);
        lay->addWidget(view);
        resize(640, 480);
    }
private:
    void onLoadFinished(bool ok){
        button->setEnabled(ok);
    }
    void onClicked(){
        progressbar->setRange(0, 0);
        QString fn = "/Users/s710/Downloads/test.pdf";
        printer.setOutputFileName(fn);
        view->page()->print(&printer, [this](bool ok){
            qDebug() << ok;
            progressbar->setRange(0, 1);
        });
    }
private:
    QPushButton *button;
    QProgressBar *progressbar;
    QWebEngineView *view;
    QPrinter printer;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

这篇关于如何从 QWebEngineView 打印的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆