我将您的问题总结如下:
- 是否需要 QWebChannel 才能在 WebEngine 中注册 JavaScript 函数?
- 在哪里可以找到 QWebChannel.js
- 如何将 JS 与 C++ 以及 C++ 与 JS 进行通信
首先,让我们来玩一个简单的代码:
#include <QApplication>
#include <QDebug>
#include <QWebEngineView>
#include <QWebChannel>
// ... DEFINITIONS HERE
auto main( int argn, char* argv[] )-> int
{
QApplication app(argn, argv);
QWebEngineView browser;
browser.resize(QSize(800,600));
browser.show();
browser.load(QUrl("http://www.wikipedia.org"));
// .. SETUP HERE
QObject::connect(&browser, &QWebEngineView::loadFinished, [&browser](bool ok)
{
qDebug()<<"Load Finished " << ok;
// TEST CODE HERE
));
return app.exec();
}
说明:此代码创建一个 Qt 应用程序,创建一个 QWebEngineView 并设置一些最小属性以使其可见。
'Wikipedia' 的页面在内部是loaded,并且在页面最终加载时连接了一个信号/插槽事件以打印一些日志。
如何在C++中调用JS函数?
您可以使用QWebEnginePage::runJavaScript 调用JS,如下所示。将此代码添加到TEST CODE HERE。
QString code = QStringLiteral(
R"DELIM(
var links = document.getElementsByTagName('a');
for ( var i=0; i<links.length; ++i)
{
links[i].style.backgroundColor = 'yellow';
};
)DELIM");
browser.page()->runJavaScript(code, 42);
说明:此代码在上下文 ID 42 上执行一些 JS 到浏览器中,避免与页面 ID 0 的默认上下文冲突。该脚本将每个链接的背景颜色更改为黄色。
如何从 JS 调用 C++?
在这种情况下,我们需要 QWebChannel 机制来将 C++ 对象注册到 JavaScript 中。
首先,让我们创建可从 JS 调用的 C++ 接口(在 DEFINITION 中):
class JsInterface: public QObject
{
Q_OBJECT
public:
/// Log, for debugging
Q_INVOKABLE void log(const QString& str) const
{
qDebug() << "LOG from JS: " << str;
}
};
#include "main.moc"
说明:此代码声明并定义了一个 QObject 类,其中包含一个简单的log 函数。声明函数Q_INVOKABLE 很重要,否则JavaScript 找不到它!由于声明与其余代码位于同一文件中,因此我们在之后包含 QT 中的 auto-moc 文件(它是 main.moc,因为我的文件是 main.cpp)。
在 DEFINITION 中创建一个函数,该函数返回 JavaScript QWebChannel.js 内容。 QWebChannel.js 的内容可以在您的 QT 库中找到(./5.12.2/Src/qtwebchannel/examples/webchannel/shared/qwebchannel.js 或 ./Examples/Qt-5.12.2/webchannel/shared/qwebchannel。 js)。您可以直接在您的页面中加载它。
在DECLARATION 部分,追加:
QString qWebChannelJs()
{
return R"DELIMITER(
// COPY HERE ALL THE FILE
)DELIMITER";
}
我们将它注入到我们的代码中(附加到TEST CODE HERE 部分):
browser.page()->runJavaScript(qWebChannelJs(), 42);
我们需要在 C++ 端设置QWebChannel(SETUP 部分):
QWebChannel channel;
JsInterface jsInterface;
browser.page()->setWebChannel(&channel, 42);
channel.registerObject(QString("JsInterface"), &jsInterface);
解释:我们创建一个频道,JsInterface 对象并将它们注册到浏览器中。我们需要使用相同的上下文 id 42(但可以是 0 到 255 之间的另一个数字)。
最后,在我们的 JS 代码中,我们访问通道并调用接口的函数(附加到TEST CODE 部分):
QString code2 = QStringLiteral(
R"DELIM(
window.webChannel = new QWebChannel(qt.webChannelTransport, function( channel)
{
var cpp = channel.objects.JsInterface;
cpp.log("Hello from JavaScript");
});
)DELIM");
browser.page()->runJavaScript(code2, 42);
注意事项
值得一提的是,从 C++ 到 JavaScript 或从 JavaScript 到 C++ 的任何调用都通过一个异步的进程间通信 (IPC)。这意味着 runJavaScript 在 JavaScript 执行之前返回,而 JavaScript 在 C++ log 执行之前返回。
完整代码
#include <QApplication>
#include <QDebug>
#include <QWebEngineView>
#include <QWebChannel>
QString qWebChannelJs()
{
return R"DELIMITER(
// TODO INSERT JS code here
)DELIMITER";
}
class JsInterface: public QObject
{
Q_OBJECT
public:
/// Log, for debugging
Q_INVOKABLE void log(const QString& str) const
{
qDebug() << "LOG from JS: " << str;
}
};
#include "main.moc"
auto main( int argn, char* argv[] )-> int
{
QApplication app(argn, argv);
QWebEngineView browser;
browser.resize(QSize(800,600));
browser.show();
browser.load(QUrl("http://www.wikipedia.org"));
// .. SETUP HERE
QWebChannel channel;
JsInterface jsInterface;
browser.page()->setWebChannel(&channel, 42);
channel.registerObject(QString("JsInterface"), &jsInterface);
QObject::connect(&browser, &QWebEngineView::loadFinished, [&browser](bool ok)
{
qDebug()<<"Load Finished " << ok;
// TEST CODE HERE
QString code = QStringLiteral(
R"DELIM(
var links = document.getElementsByTagName('a');
for ( var i=0; i<links.length; ++i)
{
links[i].style.backgroundColor = 'yellow';
};
)DELIM");
browser.page()->runJavaScript(code, 42);
browser.page()->runJavaScript(qWebChannelJs(), 42);
QString code2 = QStringLiteral(
R"DELIM(
window.webChannel = new QWebChannel(qt.webChannelTransport, function( channel)
{
var cpp = channel.objects.JsInterface;
cpp.log("Hello from JavaScript");
});
)DELIM");
browser.page()->runJavaScript(code2, 42);
});
return app.exec();
}
相关主题:
How to setup QWebChannel JS API for use in a QWebEngineView?
外部文档:
https://doc.qt.io/qt-5/qwebengineview.html
https://doc.qt.io/qt-5/qwebchannel.html
https://doc.qt.io/qt-5/qtwebengine-webenginewidgets-contentmanipulation-example.html