use*_*305 16 javascript c++ qt
我正在使用新的WebEngine来玩和学习.我一直在尝试使用Qt WebKit找到一些类似的方法: addToJavaScriptWindowObject()
我发现使用Qt WebEngine,我必须使用QWebChannel
向Javascript窗口对象注册函数.如果这是正确的,它将带我到以下问题.
我在我的电脑上安装了Qt 5.4.0.我注意到qwebchannel.js
在我的计算机上安装的SDK中找不到.我在Git源代码中找到了它.
如果我有一个Qt原生桌面应用程序,QWebEnginePage
并且QWebEngineView
,我需要能够在Javascript窗口对象上注册函数吗?
我的桌面应用程序自动导航到我创建的http页面.所以我可以访问连接到的内容QWebEngineView
.
采取了哪些措施让我可以做到这一点?
IAm*_*PLS 15
在Qt5.6中,如果你想让C++部分和JavaScript进行通信,唯一的方法就是在QWebEngineView上使用QWebChannel,如你所说.你在.cpp
文件中这样做:
m_pView = new QWebEngineView(this);
QWebChannel * channel = new QWebChannel(page);
m_pView->page()->setWebChannel(channel);
channel->registerObject(QString("TheNameOfTheObjectUsed"), this);
Run Code Online (Sandbox Code Playgroud)
在这里,您只需说明您注册了一个名为TheNameOfTheObjectUsed
JS的可用对象.现在,这是JS方面使用的代码部分:
new QWebChannel(qt.webChannelTransport, function (channel) {
// now you retrieve your object
var JSobject = channel.objects.TheNameOfTheObjectUsed;
});
Run Code Online (Sandbox Code Playgroud)
现在,如果你想在JS方面检索类的一些属性,你需要在C++端有一个方法,它返回一个字符串,一个整数,一个长...这就是它在C++方面的样子,在你的.h
:
Q_INVOKABLE int getInt();
Q_PROPERTY(int myIntInCppSide READ getInt);
Run Code Online (Sandbox Code Playgroud)
现在,你在JS方面得到这样的int:
var myIntInJSside= JSobject.myIntInCppSide;
Run Code Online (Sandbox Code Playgroud)
这是一个非常简单的解释,我建议你观看这个对我非常有用的视频.此外,您可能想要阅读有关QWebChannel提供的JavaScript API的更多信息,以及有关QWebChannel的文档.
希望有所帮助!
我将您的问题总结如下:
我将逐步解释该代码。在以下代码片段中,有一些部分标记为
DEFINITIONS
、SETUP
和TEST
。以下代码将被插入其中。
首先,让我们看一个简单的代码:
#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();
}
Run Code Online (Sandbox Code Playgroud)
说明:此代码创建一个 Qt 应用程序,创建一个 QWebEngineView 并设置一些最小属性以使其可见。来自“维基百科”的页面被load
编辑在里面,并且信号/槽事件被连接以在页面最终加载时打印一些日志。
您可以简单地使用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);
Run Code Online (Sandbox Code Playgroud)
说明:此代码在浏览器中在上下文 ID 上执行一些 JS 42
,避免与页面 ID 的默认上下文发生冲突0
。该脚本将每个链接的背景颜色更改为黄色。
在这种情况下,我们需要 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"
Run Code Online (Sandbox Code Playgroud)
说明:此代码声明并定义了一个 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";
}
Run Code Online (Sandbox Code Playgroud)
我们将它注入到我们的代码中(将其附加到TEST CODE HERE
部分):
browser.page()->runJavaScript(qWebChannelJs(), 42);
Run Code Online (Sandbox Code Playgroud)
我们需要QWebChannel
在 C++ 端进行设置(SETUP
部分):
QWebChannel channel;
JsInterface jsInterface;
browser.page()->setWebChannel(&channel, 42);
channel.registerObject(QString("JsInterface"), &jsInterface);
Run Code Online (Sandbox Code Playgroud)
说明:我们创建一个通道、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);
Run Code Online (Sandbox Code Playgroud)
值得一提的是,从 C++ 到 JavaScript 或从 JavaScript 到 C++ 的任何调用都会经过异步的进程间通信 (IPC)。这意味着runJavaScript
在 JavaScript 执行之前返回,并且 JavaScript 在 C++log
执行之前返回。
该JsInterface
对象创建一次,必须在将通道设置到页面 ( )之前registerObject
进入。然后,每次加载页面时,都会加载 js API ( ) 并将通道设置到该页面。如果您在设置频道后注册,您将收到以下日志消息:QWebChannel
setWebChannel
runJavaScript(qWebChannelJs())
JsInterface
初始化后注册新对象,现有客户端不会收到通知!
#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();
}
Run Code Online (Sandbox Code Playgroud)
如何设置 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
Qt 现在有这方面的文档:
您必须QWebSocketServer
向您的 cpp 应用程序添加一个,该QWebEngineView
应用程序的 HTML/Javascript 将使用 WebSocket 连接到。然后用于QWebChannel
双向通信。