Results 1 to 6 of 6

Thread: QtScript : Prototype-based inheritance, wrappers and setDefaultPrototype()

  1. #1
    Join Date
    May 2009
    Posts
    6
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default QtScript : Prototype-based inheritance, wrappers and setDefaultPrototype()

    Hi everyone,

    I'm trying to use QtScript to allow "users" (just me for now :P) to control the game-engine I'm creating (nothing complicated as I'm just doing that for fun).

    I've decided to create wrappers for all the classes I want to expose to the script engine. Those wrappers inherit from QObject and QScriptable.

    As an example, let's consider the following classes:

    • Drawable (abstract): contains all information that all drawable objects share (position, name, parent, children,...)
    • MeshDrawable (extends Drawable): implements pure virtual functions for loading and drawing a mesh
    • Wrapper_Drawable: wraps a Drawable
    • Wrapper_MeshDrawable (extends Wrapper_Drawable): wraps a MeshDrawable


    Let's concentrate on the last two classes:

    Qt Code:
    1. class Wrapper_Drawable : public QObject, public QScriptable
    2. {
    3. Q_OBJECT
    4. public:
    5. explicit Wrapper_Drawable(Drawable* drawable = 0);
    6.  
    7. virtual Drawable* drawable() const;
    8.  
    9. public slots:
    10. QScriptValue getPosition() const;
    11. QScriptValue setPosition();
    12.  
    13. protected:
    14. Drawable* m_drawable;
    15. };
    16.  
    17. Q_DECLARE_METATYPE(Wrapper_Drawable*)
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. class Wrapper_MeshDrawable : public Wrapper_Drawable
    2. {
    3. Q_OBJECT
    4. public:
    5. Wrapper_MeshDrawable(MeshDrawable* meshDrawable = 0);
    6.  
    7. virtual MeshDrawable* drawable() const;
    8.  
    9. public slots:
    10. QScriptValue addTriangle();
    11. };
    12.  
    13. Q_DECLARE_METATYPE(Wrapper_MeshDrawable*)
    To copy to clipboard, switch view to plain text mode 

    I declare those classes to the script engine:

    Qt Code:
    1. Wrapper_Drawable* wrapper_drawable = new Wrapper_Drawable();
    2. QScriptValue wrapper_drawable_obj = m_scriptEngine->newQObject(wrapper_drawable);
    3. wrapper_drawable_obj.setPrototype(m_scriptEngine->newObject());
    4. m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_Drawable*>(), wrapper_drawable_obj);
    5. m_scriptEngine->globalObject().setProperty("Drawable", wrapper_drawable_obj);
    6.  
    7. Wrapper_MeshDrawable* wrapper_meshDrawable = new Wrapper_MeshDrawable();
    8. QScriptValue wrapper_meshDrawable_obj = m_scriptEngine->newQObject(wrapper_meshDrawable);
    9. wrapper_meshDrawable_obj.setPrototype(wrapper_drawable_obj);
    10. m_scriptEngine->setDefaultPrototype(qMetaTypeId<Wrapper_MeshDrawable*>(), wrapper_meshDrawable_obj);
    11. m_scriptEngine->globalObject().setProperty("MeshDrawable", wrapper_meshDrawable_obj);
    To copy to clipboard, switch view to plain text mode 

    But it doesn't do what I'm expecting (these are my questions BTW):

    • If I skip the last two lines of the two blocks above, and do qDebug() << wrapper_meshDrawable_obj.instanceOf(wrapper_drawab le_obj);, the result is false. How is that possible? Am I setting the prototype chain wrong?
    • I have read somewhere (or think I've read) that even just using the 4th line of the two blocks above (setDefaultPrototype()) should let the engine know that when it creates a new QScriptValue from a Wrapper_MeshDrawable, its prototype is the one of Wrapper_Drawable. Isn't that correct?
    • When I print the properties of Drawable, it has none. When I print the properties of MeshDrawable, it has all the properties of Drawable but not his. It seems that there is a shift in the prototype chain.


    I hope my questions are clear but I would be happy to give any further information if you need some to help me.


    Thank you very much in advance!

    Regards,


    Maximilien

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QtScript : Prototype-based inheritance, wrappers and setDefaultPrototype()

    You are doing it wrong. You should be registering default prototypes for your types (i.e. Drawable* and MeshDrawable*) and not your prototypes. Then you should be exposing instances of your types and not the prototypes. Furthermore you'll have problems while casting objects containing virtual methods.

    Qt Code:
    1. #include <QCoreApplication>
    2. #include <QScriptEngine>
    3. #include <QScriptable>
    4. #include <QPoint>
    5.  
    6. class Drawable {
    7. public:
    8. int x() const { return pt.x(); }
    9. int y() const { return pt.y(); }
    10. void setX(int xx) { pt.setX(xx); }
    11. void setY(int yy) { pt.setY(yy); }
    12. private:
    13. QPoint pt;
    14. };
    15.  
    16. class MeshDrawable : public Drawable {
    17. public:
    18.  
    19. };
    20.  
    21. class DrawablePrototype : public QObject, public QScriptable {
    22. Q_OBJECT
    23. public:
    24. DrawablePrototype(QObject *parent = 0) : QObject(parent) {}
    25. public slots:
    26. void setX(int x) {
    27. Drawable *drawable = qscriptvalue_cast<Drawable*>(thisObject());
    28. drawable->setX(x);
    29. }
    30. void setY(int y) {
    31. Drawable *drawable = qscriptvalue_cast<Drawable*>(thisObject());
    32. drawable->setY(y);
    33. }
    34. public:
    35. Q_INVOKABLE virtual int x() const {
    36. Drawable *drawable = qscriptvalue_cast<Drawable*>(thisObject());
    37. return drawable->x();
    38. }
    39. Q_INVOKABLE virtual int y() const {
    40. Drawable *drawable = qscriptvalue_cast<Drawable*>(thisObject());
    41. return drawable->y();
    42. }
    43.  
    44. private:
    45.  
    46. };
    47.  
    48. class MeshDrawablePrototype : public QObject, public QScriptable {
    49. Q_OBJECT
    50. public:
    51. MeshDrawablePrototype(QObject *parent = 0) : QObject(parent) {}
    52. public:
    53. Q_INVOKABLE virtual int x() const {
    54. MeshDrawable *drawable = qscriptvalue_cast<MeshDrawable*>(thisObject());
    55. return -drawable->x();
    56. }
    57. Q_INVOKABLE virtual int y() const {
    58. MeshDrawable *drawable = qscriptvalue_cast<MeshDrawable*>(thisObject());
    59. return -drawable->y();
    60. }
    61.  
    62. };
    63.  
    64. //QScriptValue constructDrawable(QScriptContext *context, QScriptEngine *engine) {
    65. // if (!context->isCalledAsConstructor())
    66. // return context->throwError(QScriptContext::SyntaxError, "please use the 'new' operator");
    67.  
    68. // return engine->newVariant(context->thisObject(), qVariantFromValue(new Drawable));
    69. //}
    70.  
    71.  
    72. Q_DECLARE_METATYPE(Drawable*)
    73. Q_DECLARE_METATYPE(MeshDrawable*)
    74.  
    75. #include "main.moc"
    76. #include <QtDebug>
    77.  
    78. int main(int argc, char *argv[])
    79. {
    80. QCoreApplication a(argc, argv);
    81. QScriptEngine engine;
    82. DrawablePrototype drawableProto;
    83. MeshDrawablePrototype meshProto;
    84. QScriptValue dPValue = engine.newQObject(&drawableProto);
    85. QScriptValue mPValue = engine.newQObject(&meshProto);
    86. engine.setDefaultPrototype(qMetaTypeId<Drawable*>(), dPValue);
    87. engine.setDefaultPrototype(qMetaTypeId<MeshDrawable*>(), mPValue);
    88.  
    89. mPValue.setPrototype(dPValue);
    90.  
    91. Drawable *drawable = new Drawable;
    92. MeshDrawable *meshDrawable = new MeshDrawable;
    93.  
    94. QScriptValue drawableObj = engine.newVariant(qVariantFromValue<Drawable*>(drawable));
    95. QScriptValue meshDrawableObj = engine.newVariant(qVariantFromValue<MeshDrawable*>(meshDrawable));
    96. engine.globalObject().setProperty("drawable", drawableObj);
    97. engine.globalObject().setProperty("meshDrawable", meshDrawableObj);
    98.  
    99.  
    100.  
    101. qDebug() << engine.evaluate("drawable.setX(7); drawable.x()").toString();
    102. //qDebug() << engine.evaluate("meshDrawable.setX(7); meshDrawable.x()").toString();
    103. delete drawable;
    104. delete meshDrawable;
    105. }
    To copy to clipboard, switch view to plain text mode 

    Uncommenting the second qDebug() line crashes the app, probably because the cast in setX() malforms the object.

    Anyway, if the only thing you want is to indeed have wrappers for your classes then you can do so:

    Qt Code:
    1. class Drawable_Wrapper : public QObject {
    2. Q_OBJECT
    3. public:
    4. Drawable_Wrapper(Drawable *drawable, QObject *parent = 0) : QObject(parent) { m_drawable = drawable; }
    5. public slots:
    6. virtual void setX(int x) { m_drawable->setX(x); }
    7. private:
    8. Drawable *m_drawable;
    9. };
    10.  
    11. class MeshDrawable_Wrapper : public Drawable_Wrapper {
    12. Q_OBJECT
    13. public:
    14. MeshDrawable_Wrapper(MeshDrawable *meshDrawable, QObject *parent = 0) : Drawable_Wrapper(meshDrawable, parent) {}
    15. public slots:
    16. virtual void setX(int x) { Drawable_Wrapper::setX(-x); }
    17. };
    18.  
    19. Drawable_Wrapper wrapper(new Drawable);
    20. MeshDrawable_Wrapper wrapper2(new MeshDrawable);
    21. engine.globalObject()->setProperty("drawable", engine.newQObject(&wrapper));
    22. engine.globalObject()->setProperty("meshDrawable", engine.newQObject(&wrapper2));
    To copy to clipboard, switch view to plain text mode 

    Then you have inheritance on C++ side instead of using prototypes. Not exactly the same functionality though.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    May 2009
    Posts
    6
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QtScript : Prototype-based inheritance, wrappers and setDefaultPrototype()

    Hi wysota!

    Thank you for your quick and detailed answer. Now that you show it to me, it is clear that I, in fact, missed something with this whole prototype thing.

    Although I understand the first part of your answer, I'm actually more interested in the second part of it which is still unclear to me.

    My goal is in fact to provide a Wrapper to my objects so that 1) I don't have to worry about them inheriting from QObject (to make them invokable through QtScript), 2) I can keep abstract classes abstract but still be able to use them as types in QtScript (for example, I have an array of Drawable but they all actually are MeshDrawable,...) and 3) I can easily control what is exposed without having to put Q_INVOKABLE everywhere or making my functions slots.

    I don't care about the C++ from an inheritance point of view. It seems to me that it would be easier to benefit from this mechanism but it's not that important. In contrary, on the QtScript side, it is very important that an inheritance relationship is achievable. And I also want each of the wrappers' scriptvalue I create to have the correct prototype.

    The second part of your answer seems to do that but I'm not sure of some things. When I will create a new QVariant for a Wrapper_MeshDrawable, will it have all of its method exposed without me having to set a prototype? Is it possible to make the QtScript "type" have another name than Wrapper_xxx (for example, just xxx)?

    Thank you again!

    Maximilien

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QtScript : Prototype-based inheritance, wrappers and setDefaultPrototype()

    Quote Originally Posted by ixM View Post
    My goal is in fact to provide a Wrapper to my objects so that 1) I don't have to worry about them inheriting from QObject (to make them invokable through QtScript), 2) I can keep abstract classes abstract but still be able to use them as types in QtScript (for example, I have an array of Drawable but they all actually are MeshDrawable,...) and 3) I can easily control what is exposed without having to put Q_INVOKABLE everywhere or making my functions slots.
    The big question is whether you want to create such objects from within scripts or just expose existing C++ objects (not classes) to the script.

    The second part of your answer seems to do that but I'm not sure of some things. When I will create a new QVariant for a Wrapper_MeshDrawable, will it have all of its method exposed without me having to set a prototype?
    Yes, since it is a QObject.

    Is it possible to make the QtScript "type" have another name than Wrapper_xxx (for example, just xxx)?
    Since here we only expose instances of objects then the "type" doesn't really matter as the instance is the only one of its "type" (as you can't create more instances of it) so you can treat it as an "Object". If you want to expose the type and not only the instance (by providing a constructor) then controlling the name of the "type" boils down to changing the constructor name.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    May 2009
    Posts
    6
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QtScript : Prototype-based inheritance, wrappers and setDefaultPrototype()

    Once again, thank you!

    I want to be able to expose objects from C++ but also create new instances in the QtScript. The only thing I should do therefore is to create a constructor function right?

    I think I'm getting my head around it!

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QtScript : Prototype-based inheritance, wrappers and setDefaultPrototype()

    Everything depends on how your objects should behave. Certainly providing a constructor function is a must if you want to create new C++ objects from within script environment.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. QtScript and creating non QObject based objects
    By tbscope in forum Qt Programming
    Replies: 1
    Last Post: 5th October 2011, 09:20
  2. function prototype variable declaration
    By john_god in forum General Programming
    Replies: 4
    Last Post: 31st July 2010, 19:47
  3. QtScript binding wrappers? An Easy Way?
    By Statix in forum Qt Programming
    Replies: 3
    Last Post: 27th June 2010, 18:03
  4. Replies: 0
    Last Post: 25th November 2009, 08:46
  5. Lumina GLSL IDE based on QtScript and dynamic Objects
    By oc2k1 in forum Qt-based Software
    Replies: 0
    Last Post: 12th August 2008, 05:12

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.