2016-04-11 4 views
3

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

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

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

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

EDIT 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
  • У меня есть предупреждение: свойство «Num»»объекта„WebGLView“имеет не уведомит сигнал и не является постоянным, обновление значений в HTML будет нарушено!
  • nspherefromc - количество сфер, которые будут отображаться. 50, а не 10.

Любые идеи?

EDIT 2 - вторая попытка

Я до сих пор не могу заставить его работать. Я пытался добавить новую переменную с именем больше, чтобы увидеть, если функция вызывается или если оператор ввода:

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 не вызывается. Наверное, я должен сам это назвать? И когда ? Я также пробовал больше debug в if (typeof qt! = 'Undefined') sttement, и я получил 1050 сфер.

EDIT 3 - С HTML Debugger

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. Ты знаешь почему ?

EDIT - В конце OpenGL уже инициализирован, когда получены данные из C++. Поэтому количество отображаемых сфер не соответствует запросам C++.

+0

Какая версия Qt? – IAmInPLS

+0

Qt 5.6. Спасибо за ваш вопрос, я добавил его в описание. – ElevenJune

+0

Я отредактировал свой ответ после вашего редактирования. – IAmInPLS

ответ

2

В 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; 

Это очень простое объяснение, и я рекомендую вам посмотреть this video, что было очень полезно для меня. Кроме того, вы можете прочитать больше о 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(); 

В конструкторе в.каст:

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().

+0

Это помогает! Спасибо ! Я начал смотреть видео, и теперь я собираюсь попробовать его. Еще раз спасибо :) – ElevenJune

+0

Рад помочь :) если у вас есть другие вопросы, когда вы попробуете, не стесняйтесь! – IAmInPLS

+0

Я блокирую ... Мне понравились, я даже читал другие примеры, которые работают, но у меня все еще есть проблемы. Как сделать код для вас? Комментарий или изменение? – ElevenJune