Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Creating a newable QtScript object from C++ class and extend its functions via prototype

Creating a newable QtScript object from C++ class and extend its functions via prototype

Scheduled Pinned Locked Moved General and Desktop
2 Posts 1 Posters 3.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JSchmidt
    wrote on last edited by
    #1

    Hi,
    i'm trying to wrap my head around QtScript. Right now, i'm trying to get a new-able QtScript object representation of a C++ class hierarchy, which works fine so far, using scriptValueFromQMetaObject<>() and Q_SCRIPT_DECLARE_QMETAOBJECT().

    From that point on, I want to extend this object represention with some additional functions via custom prototypes, similiar to the "Default Prototypes Example":http://doc.qt.digia.com/qt/script-defaultprototypes.html shown at Qt Ref. Doc.

    Last point doesn't work, i can compile but get the message "TypeError: Result of expression 'myFruit.eat' [undefined] is not a function" from my QtScriptEngine (according to the code snippets below).

    To show my setting...

    These is my simplified class hierarchy:
    @class Fruit{}

    class ExoticFruit : public Fruit {}

    class Cumquat : public ExoticFruit {

    public slots:
    void someNativeCppCumquatSlot();

    }

    Q_META_DECLARE(Cumquat*)
    Q_SCRIPT_DECLARE_QMETAOBJECT(Cumquat, QObject*)@

    Now I added a prototype class:
    @
    class EatableProto : public QObject
    {
    Q_OBJECT
    public:
    explicit EatableProto(QObject * parent = 0){};

    public slots:
    void eat(){ qDebug() << "yamm"; };
    }
    @

    this is my simplified scripting setup:
    @
    //ctor of scripting class
    class MyScripter::MyScripter()
    {
    m_engine = new QScriptEngine;

    //has no effect, as far as I can see
    m_eatablePrototype = new EatableProto();
    m_engine->setDefaultPrototype( qMetaTypeId<Cumquat*>(), m_engine->newObject(m_eatablePrototype) );

    // works fine
    QScriptValue scriptCumquat = m_engine->scriptValueFromMetaObject<Cumquat>();
    m_engine->globalObject().setProperty("SmallOrange",scriptCumquat);
    }@

    On QtScripting view, I want to achive something like this:
    @
    //QtScript Code:
    var myFruit = new SmallOrange();
    myFruit.someNativeCppCumquatSlot(); //works

    myFruit.eat(); //protoype slot, fails with error 'is not a function'
    @

    I'm working on the prototype approach because I want to have more ExoticFruits in near future.. lets say
    @
    class Lemon : public ExoticFruit {}
    class PineApple : public ExoticFruit {}
    ...
    @

    which are all eatable... but I want them to have eatable in scripting-world only.

    Can someone see my mistake? Any suggestions?
    JSchmidt

    1 Reply Last reply
    0
    • J Offline
      J Offline
      JSchmidt
      wrote on last edited by
      #2

      Okay, i could fix it by my own. My mistake was the usage of the out-of-box macro Q_SCRIPT_DECLARE_QMETAOBJECT() (Qt 4.8.1)

      There is nothing wrong with it, despite the fact, that behind this macro, there is a boiler plate constructor for script objects which does not set the default prototype! Maybe you could see this as a bug? I don't know.

      But more important, to use the defaultPrototype feature in the way I used it above, either you have to define your own constructor for script objects or, a more elegant way, define your own Q_SCRIPT_DECLARE_QMETAOBJECT() macro. Below there is my suggestion with defaultPrototype-Support:

      original Q_SCRIPT_DECLARE_QMETAOBJECT() macro:
      @
      #define Q_SCRIPT_DECLARE_QMETAOBJECT(T, _Arg1)
      template<> inline QScriptValue qscriptQMetaObjectConstructor<T>(QScriptContext *ctx, QScriptEngine *eng, T )
      {
      _Arg1 arg1 = qscriptvalue_cast<_Arg1> (ctx->argument(0));
      T
      t = new T(arg1);
      if (ctx->isCalledAsConstructor())
      return eng->newQObject(ctx->thisObject(), t, QScriptEngine::AutoOwnership);
      QScriptValue o = eng->newQObject(t, QScriptEngine::AutoOwnership);
      o.setPrototype(ctx->callee().property(QString::fromLatin1("prototype")));
      return o;
      }
      @

      improved suggestion with defaultPrototype-support:
      @
      #define Q_SCRIPT_DECLARE_QMETAOBJECT_DEFAULT_PROTOTYPE(T, _Arg1)
      template<> inline QScriptValue qscriptQMetaObjectConstructor<T>(QScriptContext *ctx, QScriptEngine eng, T )
      {
      _Arg1 arg1 = qscriptvalue_cast<_Arg1> (ctx->argument(0));
      T
      t = new T(arg1);
      if (ctx->isCalledAsConstructor()) {
      QScriptValue proto = eng->defaultPrototype(qMetaTypeId<T
      >());
      QScriptValue u = eng->newQObject(ctx->thisObject(), t, QScriptEngine::AutoOwnership);
      u.setPrototype(proto);
      return u;
      }
      QScriptValue o = eng->newQObject(t, QScriptEngine::AutoOwnership);
      o.setPrototype(ctx->callee().property(QString::fromLatin1("prototype")));
      return o;
      }
      @

      All needed voodoo is to ask the ScriptEngine for the defaultPrototype using the template parameter T (line 7) and setting it as prototype of the newly created script object (line 9)

      Maybe it is useful for someone out there!

      1 Reply Last reply
      0

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved