簡體   English   中英

如何從 QWebEngineView 打印

[英]How to print from QWebEngineView

我正在嘗試從我的應用程序中打印一份報告,其中涉及文本和表格。 由於QTextDocument不夠用,我決定使用QWebEngineView和更復雜的 HTML/CSS,但 Qt 富文本引擎不支持。

我能夠從視圖創建 PDF,但是我有一些普遍的誤解,因為有時它會崩潰,並且打印而不是 PDF 創建會崩潰。

這是我的嘗試:


方法一: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);

但是,這僅適用於對話框(?!)。 如果我像這樣改變它:

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

它將創建一個帶有空白頁面的 PDF。 所以我想以上只是偶然地起作用。


方法二:直接打印

這種方法崩潰了:

    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資源繁重,所以我想我可以等待它完成加載。

但是,這也會崩潰

    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的工作打印功能嗎?

在第一種方法中,我認為它失敗了,因為 HTML 或 url 尚未加載並且您想要打印文本,因此可能的解決方案是使用 loadFinished 信號開始打印並使用 pdfPrintingFinished 知道打印何時完成。

#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的范圍。

#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();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM