Как получить Javascript в QWebView для создания новых экземпляров классов на основе С++?

Я успешно добавил объект C++ в QWebFrame с помощью addToJavaScriptWindowObject, и может вызвать слот для этого объекта из javascript.

Но я действительно хочу, чтобы один из этих слотов возвращал новый объект. Например, у меня есть такой слот, который возвращает экземпляр производного класса QObject:

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

Я могу успешно вызвать этот слот из javascript, как это

   var foo=myapp.helloWorld();

Но foo кажется пустым, я не могу вызвать какие-либо слоты или получить доступ к каким-либо свойствам из Javascript.

Любые идеи о том, как я могу достичь этого?


person Paul Dixon    schedule 03.06.2009    source источник
comment
В вопросе вы имеете в виду MyApp::helloWorld, верно?   -  person jrharshath    schedule 03.06.2009


Ответы (5)


Один довольно уродливый хак, который я рассматривал, состоит в том, чтобы использовать addToJavaScriptWindowObject для удаления объекта, который я хочу вернуть, в объект окна со случайным именем, а затем вместо этого мой слот возвращает имя экземпляра объекта:

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

JS можно написать, чтобы проверить, является ли возвращаемое значение строкой, и если это так, захватить объект из окна:

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

Немного некрасиво, но сойдет, пока не появится лучший метод. В будущих версиях Qt будет унифицирована поддержка сценариев, так что все будет основано на JavaScriptCore в WebKit, так что, надеюсь, тогда это улучшится!

person Paul Dixon    schedule 03.06.2009

Вы можете назначить указатель объекта на QObject * и вернуть его.

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

Это работает для меня на порте Qt Webkit в Linux.

person Chandan    schedule 03.06.2011

В QtScript есть понятие прототипов, которое позволяет вам создать прототип C++ для значения сценария. Мы изучаем, можем ли мы соединить QtScript с JavaScriptCore, что должно также привести к возможности использования прототипов из среды JavaScript WebKit; http://doc.trolltech.com/4.5/qtscript.html#making-use-of-prototype-based-inheritance

person Henrik Hartz    schedule 04.06.2009
comment
Да, я видел, что в дорожной карте есть какая-то унификация, что было бы неплохо. Мне все равно удалось скрыть уродство моего обходного пути, поэтому написанный мной js останется в значительной степени пригодным для использования, когда появятся лучшие решения. - person Paul Dixon; 04.06.2009

Попробуйте вернуть новый объект как QObject*, а не как MyObject*. Если вы просто работаете с QtScript, вы можете вызвать qScriptRegisterMetaType, чтобы определить некоторый код для обработки преобразования MyObject * в QScriptValues ​​​​(или QVariants), но, похоже, не существует эквивалента для механизма JavaScript, используемого в QtWebKit.

Досадно, что это означает, что раскрытие вашей внутренней объектной модели для WebKit потребует либо наличия отдельного набора прокси-функций, которые преобразуют ваши указатели объектов в QObject*s, либо использования некоторых классов адаптеров для выполнения того же самого.

person Rob Knight    schedule 11.06.2009
comment
Действительно, то, что я получил, — это классы адаптеров как в C++, так и в JS, чтобы преодолеть разрыв и позволить настоящему JS чувствовать, что все происходит так, как должно. - person Paul Dixon; 11.06.2009

Этот ответ основан на ответе Пола, но немного упрощен. Протестировано и работает для Qt 5.3. Вам нужна фабрика, которая создает экземпляр объекта, а затем возвращает указатель QObject на этот объект. Класс объекта должен наследоваться от QObject, чтобы он правильно работал в JavaScript:

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

При этом вы можете сделать следующее из Javascript:

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

На данный момент у вас есть obj1, а также myobject в глобальном пространстве имен JavaScript (это просто указатели, поэтому выполняются обе следующие работы:

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

На этом этапе вы можете использовать connect в JavaScript для подключения сигналов C++ к слотам JavaScript. Более подробная информация об этом методе здесь: http://doc.qt.io/qt-5/qtwebkit-bridge.html

person Michael Franzl    schedule 05.10.2015