我将您的问题总结如下:
- 我是否需要 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 并设置一些最小属性以使其可见。来自“维基百科”的页面被load
编辑在里面,并且在页面最终加载时连接了一个信号/插槽事件以打印一些日志。
如何从 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 上执行一些 JS 到浏览器中42
,避免与页面 ID 的默认上下文冲突0
。该脚本将每个链接的背景颜色更改为黄色。
如何从 JS 调用 C++?
在这种情况下,我们需要 QWebChannel 机制将 C++ 对象注册到 JavaScript 中。
首先,让我们创建可从 JS 调用的 C++ 接口(in 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
返回 JavaScriptQWebChannel.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);
我们需要QWebChannel
在 C++ 端(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();
}
相关话题:
如何设置 QWebChannel JS API 以在 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