使用 Qt runJavaScript 函数访问 Javascript 类对象

Posted

技术标签:

【中文标题】使用 Qt runJavaScript 函数访问 Javascript 类对象【英文标题】:Access Javascript class object with Qt runJavaScript function 【发布时间】:2020-08-06 16:43:37 【问题描述】:

由于我是 javascript/html 的新手,最近我使用 Qt QWebEngineView 开始了一个项目。一段时间以来,我一直在寻找将数据从 C++ 程序共享到 Javascript 的最佳方法。到目前为止,我能够将数据发送到 Javascript 程序的唯一方法是使用 QWebEnginePage::runJavaScript 函数。我还看到有可能使用QWebChannels 描述的here,但我更喜欢QWebEnginePage::runJavaScript,因为它很简单。

到目前为止,我使用 runJavaScript 方法遇到的唯一问题是,为了编写一个变量,需要在 HTML 文件中定义它,我实际上并不能 100% 确定这是否是唯一的方法,但它一直是它对我有用的唯一方法。我目前的情况是这样的:

在 HTML 文件中:

...
        <div id="latitude" ></div>
        <div id="longitude"></div>
        <div id="heading" "></div>
...

在 C++ 文件中:

...
     double Latitude = 44.244; Longitude = 10.3; Heading = 90;
     QString jsQuery = QObject::tr(
                "document.getElementById('latitude').innerHTML  =%1; "
                "document.getElementById('longitude').innerHTML =%2; "
                "document.getElementById('heading').innerHTML   =%3;"
                ).arg(Latitude).arg(Longitude).arg(Heading));
     mapWebView->page()->runJavaScript(jsQuery);
...

通过此设置,我可以从 C++ 代码在 Javascript/HTML 端编写变量。因为使用此解决方案,我需要在 HTML 文件中为要发送的每个值创建尽可能多的单独变量,所以我想问是否可以使用类对象或 JavaScript 对象来代替使用单独的变量。我用一些方法创建了一个类来编写类成员,如下所示: 在js文件中:

...
export default class PositionState
    setPosition(latitude = 0.0, longitude = 0.0, heading = 0.0)
        this.Latitude   = latitude;
        this.Longitude  = longitude;
        this.Heading    = heading;
    
    getLatitude()
        return this.Latitude;
    
    getLongitude()
        return this.Longitude;
    
    getHeading()
        return this.Heading;
    


var obj = new PositionState();
...

使用此解决方案,如果我创建 PositionState 类的对象并从 javascript 文件中调用函数 obj.setPosition(44,10.45),则对象的类成员设置正确,但如果我从 C++ 尝试它,我会遇到一些错误。

 double Latitude = 44.244; Longitude = 10.3; Heading = 90;
 Qstring jsQuery = QObject::tr(
                    "obj.setPosition(%1, %2, %3);"
                    ).arg(Latitude).arg(Longitude).arg(Heading));
mapWebView->page()->runJavaScript(jsQuery);

如果只在 Javascript 文件中定义 obj,我会收到错误 js: Uncaught ReferenceError: obj is not defined。如果我在 HTML 文件中使用Id="obj" 定义一个变量并运行相同的脚本,我会收到错误js: Uncaught TypeError: obj.setPosition is not a function,即使我使用obj.setPosition 而不是obj.setPosition,也会发生错误。

因此,对于我几乎没有 HTML/Javascript 知识的情况来说,HTML 文件不知道我的类定义,因此无法识别 setPosition 方法。所以我的问题是是否有办法从 C++ 代码中编写类对象。

我还尝试使用像 var Position = Latitude: 0, Longitude: 0, Heading: 0 这样的 JavaScript 对象,并从 C++ 代码中运行带有 QString Position = Latitude: 40, Longitude: 9, Heading: 20; 的脚本,但也无法更改 Position 对象属性。

任何帮助将不胜感激,谢谢。

【问题讨论】:

【参考方案1】:

老实说,你似乎把事情复杂化了......

您的“更简单”的方法远不如使用 QWebChannel 在 JS 和 C++ 世界之间共享对象那么简单。此外,通过另一种方式,您将失去很多功能:在 JS 中连接到 Qt 信号、重载方法、直接从 JS 读取和设置属性...

只需使用 QWebChannel 将 QObjects 注册到 QWebEnginePage 中,将 QWebChannel 加载到您的 HTML 页面中,设置连接,就可以了!

这个article 有一个关于如何做到这一点的优秀而简单的解释(带有代码sn-ps)。

您无需重新发明***。

【讨论】:

以上是关于使用 Qt runJavaScript 函数访问 Javascript 类对象的主要内容,如果未能解决你的问题,请参考以下文章

QWebEngine:同步执行 runJavascript - QEventLoop 阻止 Javascript 调用

Qt 5.5 WebEngineView 和多点触控

QT program tips

Qt:访问在构造函数之外使用 GUI 小部件的类的函数

从 Qt creator 访问 Modern OpenGL 函数

Qt/VTK:自定义交互器类中的访问函数