具有自定义类的 QtScript instanceof 引发与原型相关的错误
Posted
技术标签:
【中文标题】具有自定义类的 QtScript instanceof 引发与原型相关的错误【英文标题】:QtScript instanceof with custom class throws prototype-related error 【发布时间】:2012-01-07 16:17:36 【问题描述】:我有一个 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
的所有孩子(实际上是包装在Wrapper_Drawable
中的Drawable 的孩子)。由于Drawable
是一个抽象类,所有的孩子其实都是MeshDrawable
s。
因为我希望用户“相信”他使用的是Drawable
s 而不是Wrapper_Drawable
s,所以我声明:
m_scriptEngine->globalObject().setProperty("Drawable", wrapper_drawable_obj);
上面声明了 wrapper_drawable_obj。
我想测试引擎是否识别Wrapper_MeshDrawable
s,即使它们是在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 有关,但我无法弄清楚它到底是什么。
提前感谢您的热心帮助。
编辑>我已经添加了ScriptManager(处理脚本引擎并声明各种类型),Wrapper_Drawable(只有一些方法,否则我无法发布此消息)和Wrapper_MeshDrawable的代码。 p>
我还仔细检查了 Wrapper_Drawable 对象上的 instanceof
,使用 Number 返回 false,使用 Object 返回 true,并使用 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);
【问题讨论】:
从一个简单的脚本对象实例开始,用这个对象验证'instanceof'操作符,然后逐步模拟你的Drawable对象中存在的继承关系,直到出现错误,这至少应该查明问题的根源 @VJovic,我今晚会发布更多代码。 @Gearoid Murphy,这正是我所做的。我测试了myDrawable instanceof Number
,它返回了false
,然后是myDrawable instanceof Object
,它返回了true
,最后是myDrawable instanceof Drawable
,它抛出了错误。
这个问题似乎已在另一个论坛中得到解决。你能消化那里你认为正确的答案,把它放在这里,并把它标记为接受吗? qtcentre.org/archive/index.php/t-47245.html
@HostileFork 尽管在 qtcentre 上提供了帮助,但我无法实现我想要的。我取得了进展,但不得不暂时停止该项目的工作。我一定会继续努力并尽快提供适当的答案。
【参考方案1】:
您需要定义原型。这很快就会变得复杂,但http://doc.qt.io/archives/qt-4.7/scripting.html#making-use-of-prototype-based-inheritance 是一个很好的参考。
【讨论】:
以上是关于具有自定义类的 QtScript instanceof 引发与原型相关的错误的主要内容,如果未能解决你的问题,请参考以下文章