Связь между C ++ и Javascript для WebGL

Мой друг и я пытаемся общаться между C ++ и Javascript.
Мы хотим визуализировать некоторые сферы в заданной позиции с помощью WebGL, встроенного в приложение C ++ / Qt (версия 5.6).

Для этого мы используем QWebView который читает файл HTML со всем кодом JS для WebGL. Это хорошо работает, у нас есть отличный 3D-рендеринг высокого уровня внутри нашего приложения. Проблема в том, что позиция известна в C ++ и должна использоваться совместно с JavaScript..

Точнее, C ++ знает количество сфер, которые нам нужно отобразить, и их положение, и должен сообщить об этом стороне Javascript. Каков наилучший способ сделать это?

Примечание: мы пытались использовать Qt Canvas3D, но он был слишком медленным по сравнению с классическим WebGL.

РЕДАКТИРОВАТЬ 1 — после первой попытки

Я пытался сделать то, что вы написали, а также прочитать несколько примеров (как это один) но я не могу заставить его работать.

Я создал подкласс QWebEngineView, где я делаю все свои инициализации и помещаю свои данные.

.ч:

#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
  • У меня предупреждение: свойство ‘num’ объекта ‘WebGLView’ не имеет сигнала уведомления и не является постоянным, обновления значений в 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’), и я получил 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. Ты знаешь почему ?

РЕДАКТИРОВАТЬ — В конце концов
OpenGL уже инициализируется при получении данных из C ++. Следовательно, количество отображаемых сфер не совпадает с тем, которое запрашивает C ++.

3

Решение

В Qt5.6, если вы хотите сделать C ++ частью и JavaScript для взаимодействия, единственный способ сделать это — использовать QWebChannel на 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 ++, который возвращает строку, целое число, длинное … Вот как это выглядит на сторона C ++, в вашем .h:

Q_INVOKABLE int getNumberOfSpheres();
Q_PROPERTY(int NumberOfSpheres READ getNumberOfSpheres);

А теперь вы получите количество сфер, подобных этому на стороне JS:

var nbSpheres = JSobject.NumberOfSpheres;

Это очень простое объяснение, и я рекомендую вам посмотреть это видео что было очень полезно для меня. Кроме того, вы можете прочитать больше о JavaScript API предоставленный QWebChannel, а также документация о 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

Теперь, когда вы будете менять свою переменную num в JS сигнал будет излучаться (numChanged), и вы сможете получить значение в соответствующем слоте с getNumber(),

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]