QtWebEngine:打印由 javascript 调用的网页
QtWebEngine: Printing a webpage invoked by javascript
从 ,我知道我可以使用 QWebEngineView::render
,传递一个指向我的 QPrinter 对象的指针以编程方式打印网页。
但是如果打印请求是由 javascript 调用的(例如从 window.print()
javascript 函数),我不知道如何捕获该请求然后移交到我的打印功能。
您使用哪个版本的 Qt?目前5.6版本不支持打印。
两年后我终于想出了解决这个问题的方法。
Qt 5.8 支持打印,但是选择完全忽略 javascript 调用的 window.print() 请求。
解决方案是注入一些 javascript 来覆盖 window.print() 函数:
class JavascriptInvokedPrintComm : public QWebChannel
{
Q_OBJECT
public:
JavascriptInvokedPrintComm(QObject *parent) : QWebChannel(parent)
{
registerObject("webEngineViewBridge", this);
}
public slots:
void print()
{
emit printRequest();
}
signals:
void printRequest();
};
class MyWebEngineView : public QWebEngineView
{
Q_OBJECT
public:
MyWebEngineView(QWdidget *parent) : QWebEngineView(parent)
{
// Inject qwebchannel.js so that we can handle javascript invoked printing
QWebEngineScript webChannelJs;
webChannelJs.setInjectionPoint(QWebEngineScript::DocumentCreation);
webChannelJs.setWorldId(QWebEngineScript::MainWorld);
webChannelJs.setName("qwebchannel.js");
webChannelJs.setRunsOnSubFrames(true);
{
QFile webChannelJsFile(":/qtwebchannel/qwebchannel.js");
webChannelJsFile.open(QFile::ReadOnly);
webChannelJs.setSourceCode(webChannelJsFile.readAll());
}
page()->scripts().insert(webChannelJs);
// Inject some javascript to override the window.print() function so that we can actually catch and handle
// javascript invoked print requests
QWebEngineScript overrideJsPrint;
overrideJsPrint.setInjectionPoint(QWebEngineScript::DocumentCreation);
overrideJsPrint.setWorldId(QWebEngineScript::MainWorld);
overrideJsPrint.setName("overridejsprint.js");
overrideJsPrint.setRunsOnSubFrames(true);
overrideJsPrint.setSourceCode(
"window.print = function() { "
" new QWebChannel(qt.webChannelTransport, function(channel) { "
" var webEngineViewBridge = channel.objects.webEngineViewBridge; "
" webEngineViewBridge.print(); "
" });"
"};"
);
page()->scripts().insert(overrideJsPrint);
JavascriptInvokedPrintComm *jsInvokedPrintComm = new JavascriptInvokedPrintComm(this);
connect(jsInvokedPrintComm, &JavascriptInvokedPrintComm::printRequest, [this]()
{
QPrintDialog *prntDlg = new QPrintDialog(this);
if(!prntDlg->exec())
{
prntDlg->deleteLater();
return;
}
page()->print(prntDlg->printer(),
[prntDlg](bool ok)
{
Q_UNUSED(ok);
prntDlg->deleteLater();
}
);
});
}
}
*未经过编译测试,但概念上应该可行
从 QWebEngineView::render
,传递一个指向我的 QPrinter 对象的指针以编程方式打印网页。
但是如果打印请求是由 javascript 调用的(例如从 window.print()
javascript 函数),我不知道如何捕获该请求然后移交到我的打印功能。
您使用哪个版本的 Qt?目前5.6版本不支持打印。
两年后我终于想出了解决这个问题的方法。
Qt 5.8 支持打印,但是选择完全忽略 javascript 调用的 window.print() 请求。
解决方案是注入一些 javascript 来覆盖 window.print() 函数:
class JavascriptInvokedPrintComm : public QWebChannel
{
Q_OBJECT
public:
JavascriptInvokedPrintComm(QObject *parent) : QWebChannel(parent)
{
registerObject("webEngineViewBridge", this);
}
public slots:
void print()
{
emit printRequest();
}
signals:
void printRequest();
};
class MyWebEngineView : public QWebEngineView
{
Q_OBJECT
public:
MyWebEngineView(QWdidget *parent) : QWebEngineView(parent)
{
// Inject qwebchannel.js so that we can handle javascript invoked printing
QWebEngineScript webChannelJs;
webChannelJs.setInjectionPoint(QWebEngineScript::DocumentCreation);
webChannelJs.setWorldId(QWebEngineScript::MainWorld);
webChannelJs.setName("qwebchannel.js");
webChannelJs.setRunsOnSubFrames(true);
{
QFile webChannelJsFile(":/qtwebchannel/qwebchannel.js");
webChannelJsFile.open(QFile::ReadOnly);
webChannelJs.setSourceCode(webChannelJsFile.readAll());
}
page()->scripts().insert(webChannelJs);
// Inject some javascript to override the window.print() function so that we can actually catch and handle
// javascript invoked print requests
QWebEngineScript overrideJsPrint;
overrideJsPrint.setInjectionPoint(QWebEngineScript::DocumentCreation);
overrideJsPrint.setWorldId(QWebEngineScript::MainWorld);
overrideJsPrint.setName("overridejsprint.js");
overrideJsPrint.setRunsOnSubFrames(true);
overrideJsPrint.setSourceCode(
"window.print = function() { "
" new QWebChannel(qt.webChannelTransport, function(channel) { "
" var webEngineViewBridge = channel.objects.webEngineViewBridge; "
" webEngineViewBridge.print(); "
" });"
"};"
);
page()->scripts().insert(overrideJsPrint);
JavascriptInvokedPrintComm *jsInvokedPrintComm = new JavascriptInvokedPrintComm(this);
connect(jsInvokedPrintComm, &JavascriptInvokedPrintComm::printRequest, [this]()
{
QPrintDialog *prntDlg = new QPrintDialog(this);
if(!prntDlg->exec())
{
prntDlg->deleteLater();
return;
}
page()->print(prntDlg->printer(),
[prntDlg](bool ok)
{
Q_UNUSED(ok);
prntDlg->deleteLater();
}
);
});
}
}
*未经过编译测试,但概念上应该可行