2016-04-11 1 views
3

Mon ami et moi essayons de communiquer entre C++ et Javascript. Nous voulons rendre certaines sphères à une position donnée avec WebGL incorporé dans une application C++/Qt (version 5.6).Communication entre C++ et Javascript pour WebGL

Pour ce faire, nous utilisons un QWebView qui lit un fichier HTML avec tout le code JS pour WebGL. Cela fonctionne bien, nous avons un bon moteur de rendu 3D de haut niveau dans notre application. Le problème est que la position est connue par le C++ et doit être partagée avec le JavaScript.

Plus précisément, le C++ connaît le nombre de sphères que nous devons afficher et leur position, et doit le dire du côté Javascript. Quelle est la meilleure façon de le faire?

Remarque: Nous avons essayé d'utiliser Qt Canvas3D, mais il était trop lent par rapport au WebGL classique.

EDIT 1 - Après le premier essai

j'ai essayé de faire ce que vous avez écrit et lu aussi quelques exemples (comme celui-ci one) mais je ne peux pas le faire fonctionner.

J'ai créé une sous-classe de QWebEngineView où je fais toutes mes initialisations et met mes données.

.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; 
} 

Au début de la 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; 
}); 

Lorsque je veux accéder à la valeur:

if (typeof widget !== 'undefined') { 
    var nspherefromc = JSobject.getNumber; 
} else {var nspherefromc = 50;} 

Quand je le lance:

  • getNumber est appelé une fois, et il semble que cela vient après un appel à QWebChannel
  • Je avertissement: la propriété « num » » de l'objet « WebGLView » a notifier aucun signal et n'est pas constante, les mises à jour de valeur en HTML seront brisées!
  • nspherefromc est le nombre de sphères qui seront affichées. 50 sont affichés, pas 10.

Des idées?

EDIT 2 - Deuxième essai

Je ne peux toujours pas le faire fonctionner. J'ai essayé d'ajouter une nouvelle variable nommée plus pour voir si une fonction est appelée ou une instruction if est entré:

var more = 0; 
     if (typeof qt != 'undefined') { 
      new QWebChannel(qt.webChannelTransport, function(channel) { 
       JSobject = channel.objects.test; 
       more = 1000; 
      } 
      ); 
     } 

j'ai encore:

if (typeof JSobject !== 'undefined') { 
     nspherefromc = JSobject.num; 
    } 
    else {nspherefromc = 50;} 
    ... 
    var spheresNum = nspherefromc + more;//Number of Spheres 

Lors de l'exécution, je n'ai que 50 sphères. La fonction dans QWebChannel n'est pas appelée. Je suis supposé l'appeler moi-même? Et quand ? J'ai aussi essayé le plus de débogage dans le sttement if (typeof qt! = 'Undefined') et j'ai 1050 sphères.

EDIT 3 - Avec un Debugger 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; 

Ce qui signifie que, en dehors de la fonction, je ne peut pas atteindre JSObject plus. Est-ce que tu sais pourquoi ?

EDIT - À la fin L'OpenGL est déjà initialisé lorsque les données du C++ sont reçues. Par conséquent, le nombre de sphères affichées n'est pas celui demandé par le C++.

+0

Quelle version de Qt? – IAmInPLS

+0

Qt 5.6. Merci pour votre question, je l'ai ajouté dans la description. – ElevenJune

+0

J'ai édité ma réponse suite à votre modification. – IAmInPLS

Répondre

2

Dans Qt5.6, si vous voulez faire une partie C++ et JavaScript pour communiquer, la seule façon de le faire est d'utiliser QWebChannel sur un QWebEngineView. Vous le faites de cette façon dans le fichier .cpp:

m_pView = new QWebEngineView(this); 
QWebChannel * channel = new QWebChannel(page); 
m_pView->page()->setWebChannel(channel); 
channel->registerObject(QString("TheNameOfTheObjectUsed"), this); 

Ici, vous dites juste que vous enregistrez un objet nommé TheNameOfTheObjectUsed qui sera disponible sur le côté JS. Maintenant, c'est la partie du code à utiliser dans le côté JS:

new QWebChannel(qt.webChannelTransport, function (channel) { 
      // now you retrieve your object 
      var JSobject = channel.objects.TheNameOfTheObjectUsed; 
     }); 

Et dans votre cas, vous souhaitez récupérer le nombre de sphères, certains postes, etc. Donc, vous devez avoir une méthode sur la côté C qui retourne une chaîne, un entier, un long ... C'est à quoi il ressemble sur le côté C, dans votre .h:

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

Et maintenant, vous obtenez le nombre de sphères comme celui-ci sur la Côté JS:

var nbSpheres = JSobject.NumberOfSpheres; 

Ceci est une explication très simple, et je vous recommande de regarder this video qui a été très utile pour moi. En outre, vous voudrez peut-être en savoir plus sur le JavaScript API fourni par QWebChannel, ainsi que la documentation sur QWebChannel;

Espérons que ça aide!


Après votre édition 1

Dans votre .h, vous devez ajouter (ou modifier):

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

Dans votre constructeur dans le.cpp:

connect(this, SIGNAL(numChanged()), this, SLOT(numHasChanged())); 

Et dans le cpp lui-même:

void WebGLView::setNumber(int number) 
{ 
    m_pNumber = number; 
    emit numChanged(); 
} 

int WebGLView::getNumber() 
{ 
    return m_pNumber; 
} 


void WebGLView::numHasChanged() 
{ 
    // do anything here 
} 

Et très important dans la partie JS:

Tout d'abord, faites attention, vous copié du code sans le vérifier, si Je pense que vous vouliez dire:

if (typeof JSobject !== 'undefined') 

au lieu de

if (typeof widget !== 'undefined') 

Et puis:

var nspherefromc = JSobject.num; // this is ok 
var nspherefromc = JSobject.getNumber; // this is NOT ok 

Maintenant, chaque fois que vous allez changer votre variable num dans JS, un signal sera émis (numChanged) et vous serez en mesure d'obtenir la valeur correspondant emplacement avec un getNumber().

+0

Cela aide beaucoup! Je vous remercie ! J'ai commencé à regarder la vidéo et je vais maintenant l'essayer. Merci encore :) – ElevenJune

+0

Content de vous aider :) si vous avez d'autres questions quand vous l'essayez, n'hésitez pas! – IAmInPLS

+0

Je bloque ... J'ai fait comme vous, j'ai même lu d'autres exemples qui fonctionnent, mais j'ai encore des problèmes. Comment faire pour vous montrer plus de code? Commenter ou modifier? – ElevenJune