Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 5

Qt-interest Archive, October 2007
QtScript - testing a data model - using custom data types


Message 1 in thread

Hi all!
I would like to use QtScript to test a data model for an application.

I have two classes Scene and Panel, a Scene can contains a lot of panel
(there is some method that can
add a panel and retrieve a panel in the list (which is private)).

Both classes inherith QObject and have their method declared as public slots
in order to be used with QtScript.

Then, to create new objects from the script I try to declare the classes
starting from QMetaObject:

Q_SCRIPT_DECLARE_QMETAOBJECT(Scene, QObject*)
Q_SCRIPT_DECLARE_QMETAOBJECT(TPanel, QObject*)

...
...

QScriptValue sceneClass = m_engine.scriptValueFromQMetaObject<Scene>();
m_engine.globalObject().setProperty("Scene", sceneClass);

QScriptValue panelClass = m_engine.scriptValueFromQMetaObject<TPanel>();
m_engine.globalObject().setProperty("TPanel", panelClass);

In this manner I can create a new Scene and a new Panel with new in the
script.

When I try to retrieve a panel added to a Scene:

var s = new Scene();
s.addPanel();

var p = s.getPanel(0);

I receive, instead of a Panel type a variant one:

variant(void*, ...)

and then I cannot use any method.

How can I cast this variant in order to have a Panel type and then call its
methods ?

Probably I miss something, and I need to declare something else for the type
Scene and Panel.

Thanks in advance,

Angelo

Message 2 in thread

Angelo Moriconi wrote:
> Hi all!
> I would like to use QtScript to test a data model for an application.
>
> I have two classes Scene and Panel, a Scene can contains a lot of
> panel (there is some method that can
> add a panel and retrieve a panel in the list (which is private)).
>
> Both classes inherith QObject and have their method declared as public
> slots in order to be used with QtScript.
>
> Then, to create new objects from the script I try to declare the
> classes starting from QMetaObject:
>
> Q_SCRIPT_DECLARE_QMETAOBJECT(Scene, QObject*)
> Q_SCRIPT_DECLARE_QMETAOBJECT(TPanel, QObject*)
>
> ...
> ...
>
> QScriptValue sceneClass = m_engine.scriptValueFromQMetaObject<Scene>();
> m_engine.globalObject().setProperty("Scene", sceneClass);
>
> QScriptValue panelClass = m_engine.scriptValueFromQMetaObject<TPanel>();
> m_engine.globalObject().setProperty("TPanel", panelClass);
>
> In this manner I can create a new Scene and a new Panel with new in
> the script.
>
> When I try to retrieve a panel added to a Scene:
>
> var s = new Scene();
> s.addPanel();
>
> var p = s.getPanel(0);
>
> I receive, instead of a Panel type a variant one:
>
> variant(void*, ...)
>
> and then I cannot use any method.
>
> How can I cast this variant in order to have a Panel type and then
> call its methods ?
>
> Probably I miss something, and I need to declare something else for
> the type Scene and Panel.
>
> Thanks in advance,
>
> Angelo

Hi Angelo,
I assume your getPanel() function returns TPanel*. The problem is that
Qt Script has no conversion functions defined for TPanel*, only for the
built-in types QObject* and QWidget*, so you get the default QVariant
transportation. One way of fixing it is to change the return type of
getPanel() to be QObject*; this is OK if the sole purpose of your API is
for scripting anyway. The alternative way is to register conversion
functions for TPanel* so that QtScript will treat it like a QObject.
Copy the following chunk of code into your project:

---[ begin chunk of code ]---

template <typename Tp>
QScriptValue qScriptValueFromQObject(QScriptEngine *engine, Tp const
&qobject)
{
    return engine->newQObject(qobject);
}

template <typename Tp>
void qScriptValueToQObject(const QScriptValue &value, Tp &qobject)
{   
    qobject = qobject_cast<Tp>(value.toQObject());
}

template <typename Tp>
int qScriptRegisterQObjectMetaType(
    QScriptEngine *engine,
    const QScriptValue &prototype = QScriptValue()
#ifndef qdoc
    , Tp * /* dummy */ = 0
#endif
    )
{
    return qScriptRegisterMetaType<Tp>(engine, qScriptValueFromQObject,
                                       qScriptValueToQObject, prototype);
}

---[ end chunk of code ]---

Then do

Q_DECLARE_METATYPE(TPanel*)

...

qScriptRegisterQObjectMetaType<TPanel*>(engine);

in your application.

This issue has popped up from different sources lately, so we're
seriously contemplating the addition of qScriptRegisterQObjectMetaType()
into Qt 4.4. The docs will also be updated to state that scripting APIs
should return QObject*/QWidget* in order to work out of the box.

Regards,
Kent

--
 [ signature omitted ] 

Message 3 in thread

Thanks a lot!! It works perfectly.
Now I can use QtScript to improve testing of my apps. :)

Best regards,

Angelo

2007/10/23, Kent Hansen <khansen@xxxxxxxxxxxxx>:
>
> Angelo Moriconi wrote:
> > Hi all!
> > I would like to use QtScript to test a data model for an application.
> >
> > I have two classes Scene and Panel, a Scene can contains a lot of
> > panel (there is some method that can
> > add a panel and retrieve a panel in the list (which is private)).
> >
> > Both classes inherith QObject and have their method declared as public
> > slots in order to be used with QtScript.
> >
> > Then, to create new objects from the script I try to declare the
> > classes starting from QMetaObject:
> >
> > Q_SCRIPT_DECLARE_QMETAOBJECT(Scene, QObject*)
> > Q_SCRIPT_DECLARE_QMETAOBJECT(TPanel, QObject*)
> >
> > ...
> > ...
> >
> > QScriptValue sceneClass = m_engine.scriptValueFromQMetaObject<Scene>();
> > m_engine.globalObject().setProperty("Scene", sceneClass);
> >
> > QScriptValue panelClass = m_engine.scriptValueFromQMetaObject<TPanel>();
> > m_engine.globalObject().setProperty("TPanel", panelClass);
> >
> > In this manner I can create a new Scene and a new Panel with new in
> > the script.
> >
> > When I try to retrieve a panel added to a Scene:
> >
> > var s = new Scene();
> > s.addPanel();
> >
> > var p = s.getPanel(0);
> >
> > I receive, instead of a Panel type a variant one:
> >
> > variant(void*, ...)
> >
> > and then I cannot use any method.
> >
> > How can I cast this variant in order to have a Panel type and then
> > call its methods ?
> >
> > Probably I miss something, and I need to declare something else for
> > the type Scene and Panel.
> >
> > Thanks in advance,
> >
> > Angelo
>
> Hi Angelo,
> I assume your getPanel() function returns TPanel*. The problem is that
> Qt Script has no conversion functions defined for TPanel*, only for the
> built-in types QObject* and QWidget*, so you get the default QVariant
> transportation. One way of fixing it is to change the return type of
> getPanel() to be QObject*; this is OK if the sole purpose of your API is
> for scripting anyway. The alternative way is to register conversion
> functions for TPanel* so that QtScript will treat it like a QObject.
> Copy the following chunk of code into your project:
>
> ---[ begin chunk of code ]---
>
> template <typename Tp>
> QScriptValue qScriptValueFromQObject(QScriptEngine *engine, Tp const
> &qobject)
> {
>     return engine->newQObject(qobject);
> }
>
> template <typename Tp>
> void qScriptValueToQObject(const QScriptValue &value, Tp &qobject)
> {
>     qobject = qobject_cast<Tp>(value.toQObject());
> }
>
> template <typename Tp>
> int qScriptRegisterQObjectMetaType(
>     QScriptEngine *engine,
>     const QScriptValue &prototype = QScriptValue()
> #ifndef qdoc
>     , Tp * /* dummy */ = 0
> #endif
>     )
> {
>     return qScriptRegisterMetaType<Tp>(engine, qScriptValueFromQObject,
>                                        qScriptValueToQObject, prototype);
> }
>
> ---[ end chunk of code ]---
>
> Then do
>
> Q_DECLARE_METATYPE(TPanel*)
>
> ...
>
> qScriptRegisterQObjectMetaType<TPanel*>(engine);
>
> in your application.
>
> This issue has popped up from different sources lately, so we're
> seriously contemplating the addition of qScriptRegisterQObjectMetaType()
> into Qt 4.4. The docs will also be updated to state that scripting APIs
> should return QObject*/QWidget* in order to work out of the box.
>
> Regards,
> Kent
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with
> "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>

Message 4 in thread

I *just* ran into the same issue and "fixed" it with 
qScriptRegisterMetaType.

However I ran into difficulty at first when I tried to use FsObj* 
instead of
FsObjPtr (typedef) below. My final (FsObjPtr) solutions was:

qScriptRegisterMetaType<FsObjPtr>(engine,FsObj::toScriptValue,
                                         FsObj::fromScriptValue);

Where FsObj is a class derived from QObject and FsObjPtr
is: typedef FsObj* FsObjPtr;
and:
QScriptValue
FsObj::toScriptValue(QScriptEngine* engine,const FsObjPtr& fsObj)
{
    FsObj* nonConstFsObj = const_cast<FsObj*>(fsObj);
    return engine->newQObject(nonConstFsObj);
}
void
FsObj::fromScriptValue(const QScriptValue& scriptValue,FsObjPtr& fsObj)
{
    QObject* qobj = scriptValue.toQObject();
    fsObj = static_cast<FsObj*>(qobj);
}

I found with g++ 4.1.2 I *had* to use the typedef FsObjPtr or g++ would
complain about not finding a proper match when I tried to call
qScriptRegisterMetaType.

I'm not all that proficient with templates (yet) so I'm not sure if this
is a g++ problem, a C++ templeate design issue or something to do with
how qScriptRegisterMetaType is defined.

Kent Hansen wrote:
> Angelo Moriconi wrote:
>   
>> Hi all!
>> I would like to use QtScript to test a data model for an application.
>>
>> I have two classes Scene and Panel, a Scene can contains a lot of
>> panel (there is some method that can
>> add a panel and retrieve a panel in the list (which is private)).
>>
>> Both classes inherith QObject and have their method declared as public
>> slots in order to be used with QtScript.
>>
>> Then, to create new objects from the script I try to declare the
>> classes starting from QMetaObject:
>>
>> Q_SCRIPT_DECLARE_QMETAOBJECT(Scene, QObject*)
>> Q_SCRIPT_DECLARE_QMETAOBJECT(TPanel, QObject*)
>>
>> ...
>> ...
>>
>> QScriptValue sceneClass = m_engine.scriptValueFromQMetaObject<Scene>();
>> m_engine.globalObject().setProperty("Scene", sceneClass);
>>
>> QScriptValue panelClass = m_engine.scriptValueFromQMetaObject<TPanel>();
>> m_engine.globalObject().setProperty("TPanel", panelClass);
>>
>> In this manner I can create a new Scene and a new Panel with new in
>> the script.
>>
>> When I try to retrieve a panel added to a Scene:
>>
>> var s = new Scene();
>> s.addPanel();
>>
>> var p = s.getPanel(0);
>>
>> I receive, instead of a Panel type a variant one:
>>
>> variant(void*, ...)
>>
>> and then I cannot use any method.
>>
>> How can I cast this variant in order to have a Panel type and then
>> call its methods ?
>>
>> Probably I miss something, and I need to declare something else for
>> the type Scene and Panel.
>>
>> Thanks in advance,
>>
>> Angelo
>>     
>
> Hi Angelo,
> I assume your getPanel() function returns TPanel*. The problem is that
> Qt Script has no conversion functions defined for TPanel*, only for the
> built-in types QObject* and QWidget*, so you get the default QVariant
> transportation. One way of fixing it is to change the return type of
> getPanel() to be QObject*; this is OK if the sole purpose of your API is
> for scripting anyway. The alternative way is to register conversion
> functions for TPanel* so that QtScript will treat it like a QObject.
> Copy the following chunk of code into your project:
>
> ---[ begin chunk of code ]---
>
> template <typename Tp>
> QScriptValue qScriptValueFromQObject(QScriptEngine *engine, Tp const
> &qobject)
> {
>     return engine->newQObject(qobject);
> }
>
> template <typename Tp>
> void qScriptValueToQObject(const QScriptValue &value, Tp &qobject)
> {   
>     qobject = qobject_cast<Tp>(value.toQObject());
> }
>
> template <typename Tp>
> int qScriptRegisterQObjectMetaType(
>     QScriptEngine *engine,
>     const QScriptValue &prototype = QScriptValue()
> #ifndef qdoc
>     , Tp * /* dummy */ = 0
> #endif
>     )
> {
>     return qScriptRegisterMetaType<Tp>(engine, qScriptValueFromQObject,
>                                        qScriptValueToQObject, prototype);
> }
>
> ---[ end chunk of code ]---
>
> Then do
>
> Q_DECLARE_METATYPE(TPanel*)
>
> ...
>
> qScriptRegisterQObjectMetaType<TPanel*>(engine);
>
> in your application.
>
> This issue has popped up from different sources lately, so we're
> seriously contemplating the addition of qScriptRegisterQObjectMetaType()
> into Qt 4.4. The docs will also be updated to state that scripting APIs
> should return QObject*/QWidget* in order to work out of the box.
>
> Regards,
> Kent
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>   

--
 [ signature omitted ] 

Message 5 in thread

On 10/23/07, Peter Hackett <peter@xxxxxxxxxxxx> wrote:
> However I ran into difficulty at first when I tried to use FsObj*
> instead of
> FsObjPtr (typedef) below. My final (FsObjPtr) solutions was:

IIRC the name of the registered type must match that you use. eg. you
can use either FsObj * or FsObjPtr but you can't mix the two unless
you register both types. Under the hood there is a string comparison
used to look things up. Note I haven't looked at the implementation of
this for a while so this should probably taken with a pinch of salt.

Cheers

Rich.

--
 [ signature omitted ] 

Message 6 in thread

I didn't have a mis-match when I was using FsObj*. I was using it
consistently throughout all the code.

However, with the existing (working) code, I'm (still) using
Q_DECLARE_METATYPE(FsObj*)
rather than
Q_DECLARE_METATYPE(FsObjPtr)

(The above may be non-sequitur if my inference on your meaning of 
"registered"
is incorrect.)

Also, just in case there was any mis-understanding: The problem seemed to be
wholly a g++ compilation (template) issue. With FsObj* I was never able 
to get it to compile
so I have no idea if it would have worked or not if it did compile. To 
get it to compile,
I simple replaced all FsObj* (strings) in code having to do with the 
qScriptRegisterMetaType
with FsObjPtr (and declared the typedef) and then all was happy.

Richard Moore wrote:
> On 10/23/07, Peter Hackett <peter@xxxxxxxxxxxx> wrote:
>   
>> However I ran into difficulty at first when I tried to use FsObj*
>> instead of
>> FsObjPtr (typedef) below. My final (FsObjPtr) solutions was:
>>     
>
> IIRC the name of the registered type must match that you use. eg. you
> can use either FsObj * or FsObjPtr but you can't mix the two unless
> you register both types. Under the hood there is a string comparison
> used to look things up. Note I haven't looked at the implementation of
> this for a while so this should probably taken with a pinch of salt.
>
> Cheers
>
> Rich.
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>   

--
 [ signature omitted ] 

Message 7 in thread

This may only be tangentially related to what Angelo needs to do, but 
the phrase
"test a data model" caught my eye. I discovered:

ModelText  http://labs.trolltech.com/page/Projects/Itemview/Modeltest

on Trolltech labs and have found it to be extremely useful in understanding
and debugging the qt4 Model/View stuff. It's very easy to use. You just put:

 ModelTest myModelTest(/*QAbstractItemModel* */model,/*QObject* */parent);

in your code and your done. When constructed, the ModelTest does all 
sorts of consistency
checks to make sure your model is behaving correctly.

Angelo Moriconi wrote:
> Hi all!
> I would like to use QtScript to test a data model for an application.
>
> I have two classes Scene and Panel, a Scene can contains a lot of 
> panel (there is some method that can
> add a panel and retrieve a panel in the list (which is private)).
>
> Both classes inherith QObject and have their method declared as public 
> slots in order to be used with QtScript.
>
> Then, to create new objects from the script I try to declare the 
> classes starting from QMetaObject:
>
> Q_SCRIPT_DECLARE_QMETAOBJECT(Scene, QObject*)
> Q_SCRIPT_DECLARE_QMETAOBJECT(TPanel, QObject*)
>
> ...
> ...
>
> QScriptValue sceneClass = m_engine.scriptValueFromQMetaObject<Scene>();
> m_engine.globalObject().setProperty("Scene", sceneClass);
>
> QScriptValue panelClass = m_engine.scriptValueFromQMetaObject<TPanel>();
> m_engine.globalObject().setProperty("TPanel", panelClass);
>
> In this manner I can create a new Scene and a new Panel with new in 
> the script.
>
> When I try to retrieve a panel added to a Scene:
>
> var s = new Scene();
> s.addPanel();
>
> var p = s.getPanel(0);
>
> I receive, instead of a Panel type a variant one:
>
> variant(void*, ...)
>
> and then I cannot use any method.
>
> How can I cast this variant in order to have a Panel type and then 
> call its methods ?
>
> Probably I miss something, and I need to declare something else for 
> the type Scene and Panel.
>
> Thanks in advance,
>
> Angelo
>
>
>
>

--
 [ signature omitted ]