How to get Javascript in a QWebView to create new instances of C++ based classes?
Asked Answered
E

5

6

I've successfully added an C++ object to a QWebFrame with addToJavaScriptWindowObject, and can call a slot on that object from javascript.

But what I really want to do is have one of those slots return a new object. For example, I have a slot like this, which returns a QObject derived class instance:

   MyObject* MyApp::helloWorld()
   {
          //MyObject is dervied from QObject
          return new MyObject();
   }

I can call this slot from javascript successfully like this

   var foo=myapp.helloWorld();

But foo appears to be empty, I can't call any slots or access any properties on it from Javascript.

Any ideas on how I can achieve this?

Enesco answered 3/6, 2009 at 7:52 Comment(1)
In the question you mean MyApp::helloWorld, right?Pusillanimity
E
3

One rather ugly hack I've considered is to use addToJavaScriptWindowObject to drop the object I want to return into the window object with a random name, then have my slot return the name of the object instance instead:

QString MyApp::helloWorld()
{
     //general a unique name for the js variable
     QString name=getRandomVariableName();

     //here's the object we want to expose to js
     MyObject* pReturn=new MyObject();

     //we make attach our object to the js window object    
     getWebFrame()->addToJavaScriptWindowObject(name, pReturn,
         QScriptEngine::ScriptOwnership);  

     //tell js the name we used
     return name;
}

The JS can be written to check if the return value is a string, and if it is, grab the object from the window.:

var foo=myapp.helloWorld();
if (typeof foo == "string")
{
    foo=window[foo];
}

A little ugly, but will get me by until a better method comes along. Future Qt versions are going unify the scripting support so that it's all based on the JavaScriptCore in WebKit, so hopefully this will improve then!

Enesco answered 3/6, 2009 at 20:31 Comment(0)
M
2

You can assign your Object pointer to a QObject * and return that.

    QObject * obj = new MyObject();
    return obj;

That is working for me on Qt Webkit port on Linux.

Meteor answered 3/6, 2011 at 7:22 Comment(0)
S
1

QtScript has the notion of prototypes - which allows you to create a C++ prototype for a script value. We are investigating wether we can bridge QtScript with JavaScriptCore - which should result in the possibility of using prototypes from WebKit's JavaScript environment as well; http://doc.trolltech.com/4.5/qtscript.html#making-use-of-prototype-based-inheritance

Subcontraoctave answered 4/6, 2009 at 14:51 Comment(1)
Yes, I saw that some unification is on the roadmap, which would will be nice. I've mananged to hide the "ugliness" of my workaround anyway, so the the js I write will remain largely usable when a better solutions comes along.Enesco
O
1

Try returning your new object as a QObject* rather than a MyObject*. If you're just working with QtScript, then you can call qScriptRegisterMetaType to define some code for handling conversion of MyObject*s into QScriptValues (or QVariants), but there doesn't seem to be an equivalent for the JavaScript engine used in QtWebKit.

Annoyingly, this means that exposing your internal object model to WebKit will involve either having a separate set of proxy functions that convert your object pointers to QObject*s, or using adapter classes of some kind to do the same thing.

Ours answered 11/6, 2009 at 15:55 Comment(1)
Indeed, what I've wound up with is adapter classes in both C++ and JS to bridge the gap and let the "real" JS feel like everything is happening as it should.Enesco
B
0

This answer is based on Paul's answer, but a bit simplified. Tested and working for Qt 5.3. You need a factory that instantiates an object, and then returns a QObject pointer to this object. The object's class has to inherit from QObject so that it works properly in JavaScript:

QObject * MyApp::createInstance(QString objname) {
    MyClass * obj = new MyClass(this);
    m_mainWindow->webView->page()->mainFrame()->addToJavaScriptWindowObject(objname, obj, QWebFrame::ScriptOwnership);
    return obj;
}

With this, you can do the following from Javascript:

var myobject = MyApp.createInstance("obj1");

At this point, you have obj1 as well as myobject in the global JavaScript namespace (they are just pointers, so doing both of the following works:

myobject.testmethod();
obj1.testmethod();

At this point, you can use connect in JavaScript to connect C++ signals to JavaScript slots. More information on this technique here: http://doc.qt.io/qt-5/qtwebkit-bridge.html

Basanite answered 5/10, 2015 at 4:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.