如何使用Qt WebEngine和QWebChannel?

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)

在这里,您只需说明您注册了一个名为TheNameOfTheObjectUsedJS的可用对象.现在,这是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的文档.

希望有所帮助!


Adr*_*ire 8

我将您的问题总结如下:

  1. 我需要 QWebChannel 在 WebEngine 中注册 JavaScript 函数吗?
  2. 在哪里可以找到 QWebChannel.js
  3. 如何将 JS 与 C++ 以及 C++ 与 JS 进行通信

我将逐步解释该代码。在以下代码片段中,有一些部分标记为DEFINITIONSSETUPTEST。以下代码将被插入其中。

首先,让我们看一个简单的代码:

#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编辑在里面,并且信号/槽事件被连接以在页面最终加载时打印一些日志。

如何从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);
Run Code Online (Sandbox Code Playgroud)

说明:此代码在浏览器中在上下文 ID 上执行一些 JS 42,避免与页面 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"
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 setWebChannelrunJavaScript(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


ben*_*diy 0

Qt 现在有这方面的文档:

Qt WebChannel 独立示例

您必须QWebSocketServer向您的 cpp 应用程序添加一个,该QWebEngineView应用程序的 HTML/Javascript 将使用 WebSocket 连接到。然后用于QWebChannel双向通信。