У меня есть проект Qt, который использует модуль QtScript, чтобы сделать некоторые компоненты моего приложения доступными для сценариев.
После нескольких попыток сделать существующие классы непосредственно используемыми в QtScript, я решил использовать классы-обертки, которые наследуютQObject и QScriptable (главным образом потому, что у меня есть некоторые производные от qobject классы, которые наследуются другими, которые либо наследуют QObject, либо нет, и поэтому я не мог обрабатывать все мои классы единообразно).
Я сейчаспытаясь использовать наследование на основе прототипов.
Я должен классы Drawable
и MeshDrawable
, которые имеют соответствующие оболочки Wrapper_Drawable
и Wrapper_MeshDrawable
.MeshDrawable
наследует Drawable
и Wrapper_MeshDrawable
наследует Wrapper_Drawable
.
Я сообщаю обоим классам механизм сценариев (m_scriptEngine
):
Wrapper_Drawable* wrapper_drawable = new Wrapper_Drawable();
QScriptValue wrapper_drawable_obj = m_scriptEngine->newQObject(wrapper_drawable);
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_Drawable*>(),
wrapper_drawable_obj);
Wrapper_MeshDrawable* wrapper_meshDrawable = new Wrapper_MeshDrawable();
QScriptValue wrapper_meshDrawable_obj = m_scriptEngine->newQObject(wrapper_meshDrawable);
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_MeshDrawable*>(),
wrapper_meshDrawable_obj);
Если яне ошибаюсь, док говорит, что механизм сценариев применяет прототип Wrapper_Drawable
к объектам типа Wrapper_MeshDrawable
, поскольку они имеют отношение наследования в C ++.
У меня есть метод Wrapper_Drawable::drawables()
, который возвращает вседети Wrapper_Drawable
(на самом деле дети Drawable, завернутые в Wrapper_Drawable
).Поскольку Drawable
является абстрактным классом, все дети на самом деле MeshDrawable
с.
Поскольку я хочу, чтобы пользователь "поверил", что он использует Drawable
с, а не Wrapper_Drawable
с, яобъявляется:
m_scriptEngine->globalObject().setProperty("Drawable", wrapper_drawable_obj);
, где оберточный_объект был объявлен выше.
Я хотел проверить, распознает ли движок Wrapper_MeshDrawable
с, даже если они объявлены в массиве Wrapper_Drawable
s.
curChildren = myDrawable.drawables()[0];
print(curChildren instanceof Drawable);
К сожалению, instanceof выдает эту ошибку:
TypeError: instanceof called on an object with an invalid prototype property.
, если я пытаюсь сделать curChildren instanceof Number
, он возвращает false, поэтому я предполагаю, что проблема связана с Wrapper_Drawable, но яне могу понять, что это такое.
Заранее благодарю за любезную помощь.
EDIT> Я добавил код ScriptManager (обрабатывает обработчик сценариев)и объявляет различные типы), Wrapper_Drawable (только некоторые методы, в противном случае я не могу опубликовать это сообщение) и Wrapper_MeshDrawable.
Я также дважды проверил, что instanceof
в объекте Wrapper_Drawable возвращает false с Number,true с Object и выдает вышеупомянутую ошибкуили с Drawable (который, в отличие от имени говорит, объект Wrapper_Drawable).
Итак, есть код класса Wrapper_Drawable:
#ifndef WRAPPER_DRAWABLE_H
#define WRAPPER_DRAWABLE_H
#include <QObject>
#include <QScriptable>
#include "../drawable.h"
class Wrapper_Drawable : public QObject, public QScriptable
{
Q_OBJECT
public:
explicit Wrapper_Drawable(Drawable* drawable = 0, QObject *parent = 0);
virtual Drawable* drawable() const;
signals:
public slots:
QScriptValue visible() const;
virtual QScriptValue loadData();
QScriptValue rotate();
QScriptValue translate();
QScriptValue scale();
QScriptValue modelMatrix() const;
QScriptValue completeModelMatrix() const;
QScriptValue name() const;
QScriptValue setName();
QScriptValue shaderProgramName() const;
QScriptValue setShaderProgramName();
QScriptValue row() const;
QScriptValue childCount() const;
QScriptValue child() const;
QScriptValue appendChild();
QScriptValue insertChildren();
QScriptValue insertChild();
QScriptValue removeChildren();
QScriptValue children() const;
QScriptValue visibleChildren() const;
QScriptValue parent() const;
QScriptValue setParent();
protected:
Drawable* m_drawable;
};
Q_DECLARE_METATYPE(QList<Wrapper_Drawable*>)
Q_DECLARE_METATYPE(Wrapper_Drawable*)
#endif // WRAPPER_DRAWABLE_H
CPP:
#include "wrapper_drawable.h"
Wrapper_Drawable::Wrapper_Drawable(Drawable *drawable, QObject *parent) :
QObject(parent), m_drawable(drawable)
{
}
Drawable* Wrapper_Drawable::drawable() const {
return m_drawable;
}
QScriptValue Wrapper_Drawable::removeChildren() {
Wrapper_Drawable* wrapper_drawable = qscriptvalue_cast<Wrapper_Drawable*>(context()->thisObject());
if(!wrapper_drawable)
return context()->throwError(QScriptContext::TypeError, "Drawable.insertChildren: this object is not a Drawable");
Drawable* drawable = wrapper_drawable->drawable();
if(!drawable)
return context()->throwError(QScriptContext::TypeError, "Drawable.insertChildren: no Drawable wrapped");
if(argumentCount() != 1)
return context()->throwError(QScriptContext::SyntaxError, "Drawable.insertChildren takes exactly 1 argument");
// TODO: maybe allow multiple arguments
if(!argument(0).isNumber())
return context()->throwError(QScriptContext::TypeError, "Drawable.insertChildren: argument 0 should be a number");
unsigned int position = argument(0).toNumber();
if(!argument(1).isNumber())
return context()->throwError(QScriptContext::TypeError, "Drawable.insertChildren: argument 1 should be a number");
unsigned int count = argument(1).toNumber();
return engine()->toScriptValue(drawable->removeChildren(position, count));
}
QScriptValue Wrapper_Drawable::visibleChildren() const {
Wrapper_Drawable* wrapper_drawable = qscriptvalue_cast<Wrapper_Drawable*>(context()->thisObject());
if(!wrapper_drawable)
return context()->throwError(QScriptContext::TypeError, "Drawable.children: this object is not a Drawable");
Drawable* drawable = wrapper_drawable->drawable();
if(!drawable)
return context()->throwError(QScriptContext::TypeError, "Drawable.children: no Drawable wrapped");
if(argumentCount() > 0)
return context()->throwError(QScriptContext::SyntaxError, "Drawable.children does not take any argument");
QList<Drawable*> drawables = drawable->visibleChildren();
QList<Wrapper_Drawable*> wrapper_drawables;
for(QList<Drawable*>::const_iterator it = drawables.constBegin(), end = drawables.constEnd();
it != end; ++it)
{
wrapper_drawables.append(new Wrapper_Drawable(*it));
}
return engine()->toScriptValue(wrapper_drawables);
}
MeshDrawable:
#ifndef WRAPPER_MESHDRAWABLE_H
#define WRAPPER_MESHDRAWABLE_H
#include "wrapper_drawable.h"
#include "../meshdrawable.h"
class Wrapper_MeshDrawable : public Wrapper_Drawable
{
Q_OBJECT
public:
Wrapper_MeshDrawable(MeshDrawable* meshDrawable = 0, QObject *parent = 0);
virtual MeshDrawable* drawable() const;
public slots:
QScriptValue addTri();
QScriptValue addQuad();
QScriptValue setSmoothing();
};
Q_DECLARE_METATYPE(Wrapper_MeshDrawable*)
#endif // WRAPPER_MESHDRAWABLE_H
CPP:
#include "wrapper_meshdrawable.h"
Wrapper_MeshDrawable::Wrapper_MeshDrawable(MeshDrawable *meshDrawable, QObject *parent) :
Wrapper_Drawable(meshDrawable, parent)
{
}
MeshDrawable* Wrapper_MeshDrawable::drawable() const {
return static_cast<MeshDrawable*>(Wrapper_Drawable::drawable());
}
QScriptValue Wrapper_MeshDrawable::addTri() {
}
QScriptValue Wrapper_MeshDrawable::addQuad() {
}
QScriptValue Wrapper_MeshDrawable::setSmoothing() {
}
И, наконец, ScriptManager (где я объявляю различные типы обработчику сценариев):
#ifndef SCRIPTMANAGER_H
#define SCRIPTMANAGER_H
#include <QtScript/QScriptEngine>
#include <QtScriptTools/QScriptEngineDebugger>
#include <QtScriptTools/QtScriptTools>
#include <QStringList>
#include <QObject>
#include "utility.h"
class ScriptManager : public QObject {
Q_OBJECT
public:
ScriptManager();
public slots:
QString interprete(QString command);
private:
void initializeFunctions();
QScriptEngine* m_scriptEngine;
QScriptEngineDebugger* m_scriptEngineDebugger;
};
#endif // SCRIPTMANAGER_H
CPP
#include "scriptmanager.h"
#include "scenegraph.h"
#include "meshdrawable.h"
#include "objdrawable.h"
#include <QScriptValueIterator>
#include "wrappers/wrapper_camera.h"
#include "wrappers/wrapper_cameramanager.h"
#include "wrappers/wrapper_drawable.h"
#include "wrappers/wrapper_meshdrawable.h"
#include "wrappers/wrapper_drawablemanager.h"
#include "wrappers/wrapper_scenegraph.h"
#include "wrappers/wrapper_shadermanager.h"
QString ScriptManager::returnString = QString();
ScriptManager::ScriptManager() : m_scriptEngine(new QScriptEngine())
{
initializeFunctions();
}
void ScriptManager::initializeFunctions() {
qScriptRegisterQObjectMetaType<QGLShaderProgram*>(m_scriptEngine);
qScriptRegisterSequenceMetaType<QList<Wrapper_Drawable*> >(m_scriptEngine);
QScriptValue function_ls = m_scriptEngine->newFunction(scriptFunction_ls);
m_scriptEngine->globalObject().setProperty("ls", function_ls);
QScriptValue function_print = m_scriptEngine->newFunction(scriptFunction_print);
m_scriptEngine->globalObject().setProperty("print", function_print);
// m_scriptEngine->setDefaultPrototype(qMetaTypeId<Observer*>(),
// Observer::getDefaultPrototype(m_scriptEngine));
Wrapper_Drawable* wrapper_drawable = new Wrapper_Drawable();
QScriptValue wrapper_drawable_obj = m_scriptEngine->newQObject(wrapper_drawable);
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_Drawable*>(),
wrapper_drawable_obj);
m_scriptEngine->globalObject().setProperty("Drawable", wrapper_drawable_obj);
Wrapper_MeshDrawable* wrapper_meshDrawable = new Wrapper_MeshDrawable();
QScriptValue wrapper_meshDrawable_obj = m_scriptEngine->newQObject(wrapper_meshDrawable);
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_MeshDrawable*>(),
wrapper_meshDrawable_obj);
m_scriptEngine->globalObject().setProperty("MeshDrawable", wrapper_meshDrawable_obj);
Wrapper_Camera* wrapper_camera = new Wrapper_Camera();
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_Camera*>(),
m_scriptEngine->newQObject(wrapper_camera));
Wrapper_CameraManager* wrapper_cameraManager = new Wrapper_CameraManager();
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_CameraManager*>(),
m_scriptEngine->newQObject(wrapper_cameraManager));
Wrapper_DrawableManager* wrapper_drawableManager = new Wrapper_DrawableManager();
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_DrawableManager*>(),
m_scriptEngine->newQObject(wrapper_drawableManager));
Wrapper_SceneGraph* wrapper_sceneGraph = new Wrapper_SceneGraph(SceneGraph::instance());
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_SceneGraph*>(),
m_scriptEngine->newQObject(wrapper_sceneGraph));
QScriptValue object_sceneGraph = m_scriptEngine->newQObject("sceneGraph", wrapper_sceneGraph);
m_scriptEngine->globalObject().setProperty("sceneGraph", object_sceneGraph);
Wrapper_ShaderManager* wrapper_shaderManager = new Wrapper_ShaderManager();
m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_ShaderManager*>(),
m_scriptEngine->newQObject(wrapper_shaderManager));
m_scriptEngineDebugger = new QScriptEngineDebugger();
m_scriptEngineDebugger->attachTo(m_scriptEngine);
}