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

谁说我不能喝 提交于 2019-11-29 07:23:11

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!

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.

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

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.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!