我正在尝试从应用程序中打印报告,该报告涉及文本和表格。由于QTextDocument
不够用,因此我决定使用QWebEngineView
和Qt富文本引擎不支持的更复杂的HTML / CSS。
我能够从视图中创建PDF,但是我有一些普遍的误解,因为有时它会崩溃,并且还会打印而不是PDF创建崩溃。
这是我的尝试:
方法1:创建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。所以我想以上只是偶然。
方法2:直接打印
此方法崩溃:
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
...
方法3:等待加载Web视图,然后创建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
方法4:等待网络视图加载,然后打印
这也会崩溃:
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
指向我使用的打印功能吗?
答案 0 :(得分:1)
在第一种方法中,我认为它失败了,因为尚未加载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();
}