带有自定义类的QtScript instanceof会抛出与原型相关的错误

ixM*_*ixM 26 c++ qt ecma262 qtscript

我有一个Qt项目,它使用QtScript模块使我的应用程序的某些组件可编写脚本.

在多次尝试使现有类直接在QtScript中可用之后,我选择使用继承QObject和QScriptable的包装类(主要是因为我有一些非qobject派生类,这些类是由其他人继承的,它们是否继承QObject,它是因此我不可能统一对待我所有的课程).

我现在正在尝试使用基于原型的继承.

我必须有类DrawableMeshDrawable相应的包装器Wrapper_DrawableWrapper_MeshDrawable.MeshDrawable继承DrawableWrapper_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);
Run Code Online (Sandbox Code Playgroud)

如果我没有弄错,那么doc说脚本引擎会将原型应用于Wrapper_Drawable类型的对象,Wrapper_MeshDrawable因为它们在C++中具有继承关系.

我有一个方法Wrapper_Drawable::drawables(),它返回一个Wrapper_Drawable(实际上是包含在其中的Drawable的子节点Wrapper_Drawable)的所有子节点.作为Drawable一个抽象类,所有孩子实际上都是MeshDrawables.

因为我希望用户"相信"他使用Drawables而不是Wrapper_Drawables,我已经声明:

m_scriptEngine->globalObject().setProperty("Drawable", wrapper_drawable_obj);
Run Code Online (Sandbox Code Playgroud)

上面声明了wrapper_drawable_obj.


我想测试引擎是否识别Wrapper_MeshDrawables,即使它们是在一个Wrapper_Drawables 数组中声明的.

curChildren = myDrawable.drawables()[0];
print(curChildren instanceof Drawable);
Run Code Online (Sandbox Code Playgroud)

遗憾的是,instanceof抛出了这个错误:

TypeError: instanceof called on an object with an invalid prototype property.
Run Code Online (Sandbox Code Playgroud)

如果我尝试这样做curChildren instanceof Number会返回false,所以我猜这个问题与Wrapper_Drawable有关,但我无法弄清楚究竟是什么.

提前感谢您的帮助.

编辑>我添加了ScriptManager的代码(处理脚本引擎并声明各种类型),Wrapper_Drawable(只有一些方法,否则我不能发布此消息)和Wrapper_MeshDrawable.

我还在instanceofWrapper_Drawable对象上进行了双重检查,使用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
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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() {

}
Run Code Online (Sandbox Code Playgroud)

最后是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
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

小智 1

您需要定义您的原型。这很快就会变得复杂,但http://doc.qt.io/archives/qt-4.7/scripting.html#making-use-of-prototype-based-inheritance是一个很好的参考。