Мой друг и я пытаемся общаться между 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;}
Когда я запускаю это:
Есть идеи ?
РЕДАКТИРОВАТЬ 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 ++.
В 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()
,
Других решений пока нет …