C++ 和 Javascript for WebGL 之间的通信
Communication between C++ and Javascript for WebGL
我和我的朋友正在尝试在 C++ 和 Javascript 之间进行通信。
我们想在给定位置渲染一些球体,并在 C++/Qt(5.6 版)应用程序中嵌入 WebGL。
为此,我们使用 QWebView
读取 HTML 文件,其中包含 WebGL 的所有 JS 代码。这很好用,我们的应用程序中有一个很棒的高级 3D 渲染器。 问题是该位置为 C++ 所知,必须共享给 JavaScript。
更准确地说,C++ 知道我们需要显示的球体数量和它们的位置,并且必须将其告知 Javascript 端。最好的方法是什么?
注意:我们尝试使用 Qt Canvas3D,但与经典的 WebGL 相比它太慢了。
编辑 1 - 第一次尝试后
我试着按照你写的做,也读了一些例子(比如这个one)但是我做不到。
我创建了一个 QWebEngineView 的子类,我在其中进行了所有初始化并放置了我的数据。
.h :
#ifndef WEBGLVIEW_H
#define WEBGLVIEW_H
#include <QObject>
#include <QtWebEngineWidgets>
#include <QtWebChannel/QtWebChannel>
class WebGLView : public QWebEngineView
{
Q_OBJECT
Q_INVOKABLE int getNumber();
Q_PROPERTY(int num READ getNumber)
public:
WebGLView(QWidget *parent = 0);
private :
QWebChannel* m_channel;
};
#endif // WEBGLVIEW_H
.cpp :
#include "WebGLView.h"
#include <QCoreApplication>
#include <QUrl>
#include <QDebug>
WebGLView::WebGLView(QWidget *parent) :
QWebEngineView(parent)
{
// Set up the communications channel
//C++ to Java test
m_channel = new QWebChannel(this);
this->page()->setWebChannel(m_channel);
m_channel->registerObject(QString("test"),this);
QString path = QCoreApplication::applicationDirPath() + "/test6.html";
this->setUrl(QUrl::fromLocalFile(path));
}
int WebGLView::getNumber()
{
qDebug() << "getNumber";
return 10;
}
JS开头:
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
...
var JSobject;
if (typeof qt != 'undefined') {new QWebChannel(qt.webChannelTransport, function(channel) {
JSobject = channel.objects.test;
} );
当我想访问值时:
if (typeof widget !== 'undefined') {
var nspherefromc = JSobject.getNumber;
} else {var nspherefromc = 50;}
当我运行它时:
- getNumber调用了一次,好像是在调用QWebChannel之后调用的
- 我有警告:对象 'WebGLView' 的 属性 'num'' 没有通知信号并且不是常量,HTML 中的值更新将被破坏!
- nspherefromc 是将显示的球体数。显示 50 个,而不是 10 个。
有什么想法吗?
编辑 2 - 第二次尝试
我仍然无法让它工作。
我尝试添加一个名为 more 的新变量,以查看是否调用了函数或输入了 if 语句:
var more = 0;
if (typeof qt != 'undefined') {
new QWebChannel(qt.webChannelTransport, function(channel) {
JSobject = channel.objects.test;
more = 1000;
}
);
}
我还有:
if (typeof JSobject !== 'undefined') {
nspherefromc = JSobject.num;
}
else {nspherefromc = 50;}
...
var spheresNum = nspherefromc + more;//Number of Spheres
当运行设置它时,我只有 50 个球体。 QWebChannel 中的函数未被调用。我想我自己称呼它?什么时候 ?
我还在 if(typeof qt != 'undefined') sttement 中尝试了更多调试,我得到了 1050 个球体。
编辑 3 - 使用 HTML 调试器
function init() {
var JSobject;
var nspherefromc = 0;
if (typeof qt !== 'undefined') {
new QWebChannel(qt.webChannelTransport, function(channel) {
JSobject = channel.objects.test;
console.log(JSobject); //-> returns the object, I can access the functions and everything
nspherefromc = JSobject.num;
console.log("in the function " + nspherefromc); //prints 5000, what i sent from C++
more = 1000;
}
);
console.log(JSobject); // prints undefined
}
console.log(JSobject); // prints undefined
if (typeof JSobject !== 'undefined') {
console.log("Yeaaaah"); //Not reached
nspherefromc = JSobject.num;
nspherefromc + 1;
}
...
console.log("when loading " + nspherefromc + " (more is = to " + more); // nsphere = 0 , more = 0
var spheresNum = nspherefromc + more;
这意味着在函数之外我无法再访问 JSobject。你知道为什么吗?
编辑 - 最后
当接收到来自 C++ 的数据时,openGL 已经初始化。因此,显示的球体数量不是 C++ 要求的数量。
在Qt5.6中,如果要让C++部分和JavaScript通信,只能使用QWebChannel on a QWebEngineView。你在 .cpp
文件中这样做:
m_pView = new QWebEngineView(this);
QWebChannel * channel = new QWebChannel(page);
m_pView->page()->setWebChannel(channel);
channel->registerObject(QString("TheNameOfTheObjectUsed"), this);
这里你就说你注册了一个对象,名字叫TheNameOfTheObjectUsed
,在JS端就可以使用了。现在,这是在 JS 端使用的代码部分:
new QWebChannel(qt.webChannelTransport, function (channel) {
// now you retrieve your object
var JSobject = channel.objects.TheNameOfTheObjectUsed;
});
在您的情况下,您想要检索球体的数量、一些位置等。因此您需要在 C++ 端有一个方法,其中 returns 一个字符串、一个整数、一个长整数。 .. 这就是 C++ 端的样子,在你的 .h
:
Q_INVOKABLE int getNumberOfSpheres();
Q_PROPERTY(int NumberOfSpheres READ getNumberOfSpheres);
现在,您在 JS 端获得了这样的球体数量:
var nbSpheres = JSobject.NumberOfSpheres;
这是一个很简单的讲解,推荐大家观看this video which was very useful to me. Also, you might want to read more about the JavaScript API provided by QWebChannel, as well as the documentation about QWebChannel;
希望对您有所帮助!
编辑后 1
在你的.h中,你需要添加(或更改):
int m_pNumber;
Q_PROPERTY(int num READ getNumber WRITE setNumber NOTIFY numChanged)
Q_INVOKABLE void setNumber(int number); // add this function to the cpp file as well
//add a signal for NOTIFY
signals:
void numChanged();
public slots:
void numHasChanged();
在 .cpp 的构造函数中:
connect(this, SIGNAL(numChanged()), this, SLOT(numHasChanged()));
在 cpp 本身中:
void WebGLView::setNumber(int number)
{
m_pNumber = number;
emit numChanged();
}
int WebGLView::getNumber()
{
return m_pNumber;
}
void WebGLView::numHasChanged()
{
// do anything here
}
并且在 JS 方面非常重要:
首先,请注意,您没有检查就复制了一些代码,所以我认为您的意思是:
if (typeof JSobject !== 'undefined')
而不是
if (typeof widget !== 'undefined')
然后:
var nspherefromc = JSobject.num; // this is ok
var nspherefromc = JSobject.getNumber; // this is NOT ok
现在,每当您在 JS 中更改变量 num
时,都会发出一个信号 (numChanged
),您将能够使用 getNumber()
。
我和我的朋友正在尝试在 C++ 和 Javascript 之间进行通信。 我们想在给定位置渲染一些球体,并在 C++/Qt(5.6 版)应用程序中嵌入 WebGL。
为此,我们使用 QWebView
读取 HTML 文件,其中包含 WebGL 的所有 JS 代码。这很好用,我们的应用程序中有一个很棒的高级 3D 渲染器。 问题是该位置为 C++ 所知,必须共享给 JavaScript。
更准确地说,C++ 知道我们需要显示的球体数量和它们的位置,并且必须将其告知 Javascript 端。最好的方法是什么?
注意:我们尝试使用 Qt Canvas3D,但与经典的 WebGL 相比它太慢了。
编辑 1 - 第一次尝试后
我试着按照你写的做,也读了一些例子(比如这个one)但是我做不到。
我创建了一个 QWebEngineView 的子类,我在其中进行了所有初始化并放置了我的数据。
.h :
#ifndef WEBGLVIEW_H
#define WEBGLVIEW_H
#include <QObject>
#include <QtWebEngineWidgets>
#include <QtWebChannel/QtWebChannel>
class WebGLView : public QWebEngineView
{
Q_OBJECT
Q_INVOKABLE int getNumber();
Q_PROPERTY(int num READ getNumber)
public:
WebGLView(QWidget *parent = 0);
private :
QWebChannel* m_channel;
};
#endif // WEBGLVIEW_H
.cpp :
#include "WebGLView.h"
#include <QCoreApplication>
#include <QUrl>
#include <QDebug>
WebGLView::WebGLView(QWidget *parent) :
QWebEngineView(parent)
{
// Set up the communications channel
//C++ to Java test
m_channel = new QWebChannel(this);
this->page()->setWebChannel(m_channel);
m_channel->registerObject(QString("test"),this);
QString path = QCoreApplication::applicationDirPath() + "/test6.html";
this->setUrl(QUrl::fromLocalFile(path));
}
int WebGLView::getNumber()
{
qDebug() << "getNumber";
return 10;
}
JS开头:
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
...
var JSobject;
if (typeof qt != 'undefined') {new QWebChannel(qt.webChannelTransport, function(channel) {
JSobject = channel.objects.test;
} );
当我想访问值时:
if (typeof widget !== 'undefined') {
var nspherefromc = JSobject.getNumber;
} else {var nspherefromc = 50;}
当我运行它时:
- getNumber调用了一次,好像是在调用QWebChannel之后调用的
- 我有警告:对象 'WebGLView' 的 属性 'num'' 没有通知信号并且不是常量,HTML 中的值更新将被破坏!
- nspherefromc 是将显示的球体数。显示 50 个,而不是 10 个。
有什么想法吗?
编辑 2 - 第二次尝试
我仍然无法让它工作。 我尝试添加一个名为 more 的新变量,以查看是否调用了函数或输入了 if 语句:
var more = 0;
if (typeof qt != 'undefined') {
new QWebChannel(qt.webChannelTransport, function(channel) {
JSobject = channel.objects.test;
more = 1000;
}
);
}
我还有:
if (typeof JSobject !== 'undefined') {
nspherefromc = JSobject.num;
}
else {nspherefromc = 50;}
...
var spheresNum = nspherefromc + more;//Number of Spheres
当运行设置它时,我只有 50 个球体。 QWebChannel 中的函数未被调用。我想我自己称呼它?什么时候 ? 我还在 if(typeof qt != 'undefined') sttement 中尝试了更多调试,我得到了 1050 个球体。
编辑 3 - 使用 HTML 调试器
function init() {
var JSobject;
var nspherefromc = 0;
if (typeof qt !== 'undefined') {
new QWebChannel(qt.webChannelTransport, function(channel) {
JSobject = channel.objects.test;
console.log(JSobject); //-> returns the object, I can access the functions and everything
nspherefromc = JSobject.num;
console.log("in the function " + nspherefromc); //prints 5000, what i sent from C++
more = 1000;
}
);
console.log(JSobject); // prints undefined
}
console.log(JSobject); // prints undefined
if (typeof JSobject !== 'undefined') {
console.log("Yeaaaah"); //Not reached
nspherefromc = JSobject.num;
nspherefromc + 1;
}
...
console.log("when loading " + nspherefromc + " (more is = to " + more); // nsphere = 0 , more = 0
var spheresNum = nspherefromc + more;
这意味着在函数之外我无法再访问 JSobject。你知道为什么吗?
编辑 - 最后 当接收到来自 C++ 的数据时,openGL 已经初始化。因此,显示的球体数量不是 C++ 要求的数量。
在Qt5.6中,如果要让C++部分和JavaScript通信,只能使用QWebChannel on a QWebEngineView。你在 .cpp
文件中这样做:
m_pView = new QWebEngineView(this);
QWebChannel * channel = new QWebChannel(page);
m_pView->page()->setWebChannel(channel);
channel->registerObject(QString("TheNameOfTheObjectUsed"), this);
这里你就说你注册了一个对象,名字叫TheNameOfTheObjectUsed
,在JS端就可以使用了。现在,这是在 JS 端使用的代码部分:
new QWebChannel(qt.webChannelTransport, function (channel) {
// now you retrieve your object
var JSobject = channel.objects.TheNameOfTheObjectUsed;
});
在您的情况下,您想要检索球体的数量、一些位置等。因此您需要在 C++ 端有一个方法,其中 returns 一个字符串、一个整数、一个长整数。 .. 这就是 C++ 端的样子,在你的 .h
:
Q_INVOKABLE int getNumberOfSpheres();
Q_PROPERTY(int NumberOfSpheres READ getNumberOfSpheres);
现在,您在 JS 端获得了这样的球体数量:
var nbSpheres = JSobject.NumberOfSpheres;
这是一个很简单的讲解,推荐大家观看this video which was very useful to me. Also, you might want to read more about the JavaScript API provided by QWebChannel, as well as the documentation about QWebChannel;
希望对您有所帮助!
编辑后 1
在你的.h中,你需要添加(或更改):
int m_pNumber;
Q_PROPERTY(int num READ getNumber WRITE setNumber NOTIFY numChanged)
Q_INVOKABLE void setNumber(int number); // add this function to the cpp file as well
//add a signal for NOTIFY
signals:
void numChanged();
public slots:
void numHasChanged();
在 .cpp 的构造函数中:
connect(this, SIGNAL(numChanged()), this, SLOT(numHasChanged()));
在 cpp 本身中:
void WebGLView::setNumber(int number)
{
m_pNumber = number;
emit numChanged();
}
int WebGLView::getNumber()
{
return m_pNumber;
}
void WebGLView::numHasChanged()
{
// do anything here
}
并且在 JS 方面非常重要:
首先,请注意,您没有检查就复制了一些代码,所以我认为您的意思是:
if (typeof JSobject !== 'undefined')
而不是
if (typeof widget !== 'undefined')
然后:
var nspherefromc = JSobject.num; // this is ok
var nspherefromc = JSobject.getNumber; // this is NOT ok
现在,每当您在 JS 中更改变量 num
时,都会发出一个信号 (numChanged
),您将能够使用 getNumber()
。