Qt-interest Archive, March 2008
Re: QtScript - returning a QObject * back to a script
Message 1 in thread
Peter Hackett wrote:
> Is "Field*" type "exported" into the script environment.
>
> I think you need to:
>
> Q_DECLARE_METATYPE(Field*)
>
> and (I think) call qScriptRegisterMetaType<Field*>(xxx,yyy,zzz)
Yes, I'm doing Q_DECLARE_METATYPE() in the headers of all of my classes.
They are all subclassed from QObject so I didn't think
qScriptRegisterMetaType() was required, since this should already be
done as part of being QObjects, right?
As per the docs, I am calling "qMetaTypeId<Field *>();" in the Field
constructor, though I'm not entirely sure why this is needed.
>
> Paul Miller wrote:
>> I'm attempting to do something documented in the QtScript reference
>> and it's not working. I must not be doing something quite right, or
>> maybe it's more complicated than it is described in the manual.
>>
>> I've exposed a global object ("root") through setProperty() as used in
>> the docs. My "root" QObject subclass has a slot:
>>
>> Field *field(const QString &name) const;
>>
>> The field() slot looks up a Field (which is derived from QObject, and
>> has a "name" property) by name.
>>
>> In my script I want to write this:
>> print(root.field("example").name);
>>
>> Now, my root object's "field" slot is getting called and returning the
>> Field *, but evaluation of the "name" property results in an
>> "undefined" result. But the result should be the QString name
>> property of the Field.
>>
>> If I change my script to this:
>> print(root.field("example"));
>>
>> I get this result:
>> QVariant(Field*)
>>
>> I'm not sure if that is correct or not, but I can't explain why the
>> "name" property of the Field won't evaluate.
>>
>> "root" also has a "name" property, and 'print(root.name);' works fine.
>>
>> Any ideas?
>>
>
> --
> 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 2 in thread
Paul Miller wrote:
> I'm attempting to do something documented in the QtScript reference
> and it's not working. I must not be doing something quite right, or
> maybe it's more complicated than it is described in the manual.
>
> I've exposed a global object ("root") through setProperty() as used in
> the docs. My "root" QObject subclass has a slot:
>
> Field *field(const QString &name) const;
>
> The field() slot looks up a Field (which is derived from QObject, and
> has a "name" property) by name.
[...]
> I get this result:
> QVariant(Field*)
>
> I'm not sure if that is correct or not, but I can't explain why the
> "name" property of the Field won't evaluate.
Hi Paul,
The C++-to-script value conversion is based on mapping a string (e.g.
"Field*") to a metatype-id, and mapping the metatype-id to a conversion
function (installed with qscriptRegisterMetaType()). The built-in types
that QtScript can handle are QObject* and QWidget* (see "Conversion
Between QtScript and C++ Types" in the docs), so I suggest using those
types in your method signatures when designing scripting APIs (just like
with the QObject-subclass-type-as-argument issue you encountered
before), unless you have special needs for how conversion should be
performed for your types.
The docs will be updated to be more explicit about this case, because I
agree it looks strange from the top-level perspective (that is, even
though you subclassed QObject and used the Q_OBJECT macro, it doesn't
really matter; all QtScript sees when your Global slot is invoked is a
return type identified by the string "Field*" -- there's no more
contextual information to go by. That's why you have to tell QtScript
what to do in such cases).
Regards,
Kent
--
[ signature omitted ]
Message 3 in thread
Kent Hansen wrote:
> Paul Miller wrote:
>> I'm attempting to do something documented in the QtScript reference
>> and it's not working. I must not be doing something quite right, or
>> maybe it's more complicated than it is described in the manual.
>>
>> I've exposed a global object ("root") through setProperty() as used in
>> the docs. My "root" QObject subclass has a slot:
>>
>> Field *field(const QString &name) const;
>>
>> The field() slot looks up a Field (which is derived from QObject, and
>> has a "name" property) by name.
> [...]
>> I get this result:
>> QVariant(Field*)
>>
>> I'm not sure if that is correct or not, but I can't explain why the
>> "name" property of the Field won't evaluate.
>
> Hi Paul,
> The C++-to-script value conversion is based on mapping a string (e.g.
> "Field*") to a metatype-id, and mapping the metatype-id to a conversion
> function (installed with qscriptRegisterMetaType()). The built-in types
> that QtScript can handle are QObject* and QWidget* (see "Conversion
> Between QtScript and C++ Types" in the docs), so I suggest using those
> types in your method signatures when designing scripting APIs (just like
> with the QObject-subclass-type-as-argument issue you encountered
> before), unless you have special needs for how conversion should be
> performed for your types.
>
> The docs will be updated to be more explicit about this case, because I
> agree it looks strange from the top-level perspective (that is, even
> though you subclassed QObject and used the Q_OBJECT macro, it doesn't
> really matter; all QtScript sees when your Global slot is invoked is a
> return type identified by the string "Field*" -- there's no more
> contextual information to go by. That's why you have to tell QtScript
> what to do in such cases).
Thanks Kent - nice summary. That really explains a lot. I was thrown off
completely because the docs make it look like qScriptRegisterMetaType is
only needed for non-QObject types.
--
[ signature omitted ]
Message 4 in thread
Paul Miller wrote:
> Kent Hansen wrote:
>> Paul Miller wrote:
>>> I'm attempting to do something documented in the QtScript reference
>>> and it's not working. I must not be doing something quite right, or
>>> maybe it's more complicated than it is described in the manual.
>>
>> Hi Paul,
>> The C++-to-script value conversion is based on mapping a string (e.g.
>> "Field*") to a metatype-id, and mapping the metatype-id to a conversion
>> function (installed with qscriptRegisterMetaType()).
[...]
>
> Thanks Kent - nice summary. That really explains a lot. I was thrown
> off completely because the docs make it look like
> qScriptRegisterMetaType is only needed for non-QObject types.
>
Hi Paul,
FYI, the related issue you reported about QObject argument conversion
(http://trolltech.com/developer/task-tracker/index_html?id=200599&method=entry)
has been fixed. You will also get more detailed error messages should
conversion fail (with a hint about looking at
qScriptRegisterMetaType()). Lastly, the docs have been updated/expanded
to cover these things in more detail (in particular that
qScriptRegisterMetaType() is needed for custom QObject types).
Thanks for the feedback, this is a great improvement.
Regards,
Kent
--
[ signature omitted ]
Message 5 in thread
In case other might find it helpful, I deal with
qscriptRegisterMetaType() with
a template:
template <typename T,typename BASE=void,bool SCRIPT_OWN = false>
// ===============
class IqtScriptHelper
// ===============
{
public:
typedef T* Tptr;
static QScriptValue toScriptValue(QScriptEngine* engine,
const Tptr& fsObj)
{
Tptr nonConstFsObj = const_cast<Tptr>(fsObj);
if ( SCRIPT_OWN ) {
return engine->newQObject(nonConstFsObj,
QScriptEngine::ScriptOwnership);
} else {
return engine->newQObject(nonConstFsObj);
}
}
static void fromScriptValue(const QScriptValue& scriptValue,
Tptr& fsObj)
{
QObject* qobj = scriptValue.toQObject();
fsObj = static_cast<Tptr>(qobj);
}
// needed these next two versions for FsContainer* (because c++ doesn't
// know that all "real" FsContainer*s are QObject*s (FsObj*s))
static QScriptValue toBASEToScriptValue(QScriptEngine* engine,
const Tptr& pt)
{
BASE* fsObj = NULL;
if ( pt != NULL ) {
Tptr nonConstPt = const_cast<Tptr>(pt);
fsObj = dynamic_cast<BASE*>(nonConstPt);
ICM_ASSERT(fsObj != NULL,"dynamic_cast<BASE*> failed",
TYPENAME(*nonConstPt));
}
if ( SCRIPT_OWN ) {
return engine->newQObject(fsObj,QScriptEngine::ScriptOwnership);
} else {
return engine->newQObject(fsObj);
}
}
static void fromScriptValueToBASE(const QScriptValue&
scriptValue,
Tptr& fsObj)
{
QObject* qobj = scriptValue.toQObject();
if ( qobj == NULL ) {
fsObj = NULL;
} else {
fsObj = dynamic_cast<Tptr>(qobj);
ICM_ASSERT(fsObj != NULL,"dynamic_cast to Tptr failed",
TYPENAME(*qobj));
}
}
};
And use it like this:
...
// FsDir*
qmetaTy =
qScriptRegisterMetaType<IqtScriptHelper<FsDir>::Tptr>(
scriptEngine,
IqtScriptHelper<FsDir>::toScriptValue,
IqtScriptHelper<FsDir>::fromScriptValue);
...
// FsContainer*
qmetaTy =
qScriptRegisterMetaType<IqtScriptHelper<FsContainer>::Tptr>(
scriptEngine,
IqtScriptHelper<FsContainer,FsObj>::toBASEToScriptValue,
// note ------
IqtScriptHelper<FsContainer,FsObj>::fromScriptValueToBASE);
// note ------
...
// FsObjIter*
qmetaTy =
qScriptRegisterMetaType<IqtScriptHelper<FsObjIter>::Tptr>(
scriptEngine,
IqtScriptHelper<FsObjIter,void,/*scriptOwn*/true>::toScriptValue,
// note -----------------
IqtScriptHelper<FsObjIter>::fromScriptValue);
...
Paul Miller wrote:
> Kent Hansen wrote:
>> Paul Miller wrote:
>>> I'm attempting to do something documented in the QtScript reference
>>> and it's not working. I must not be doing something quite right, or
>>> maybe it's more complicated than it is described in the manual.
>>>
>>> I've exposed a global object ("root") through setProperty() as used in
>>> the docs. My "root" QObject subclass has a slot:
>>>
>>> Field *field(const QString &name) const;
>>>
>>> The field() slot looks up a Field (which is derived from QObject, and
>>> has a "name" property) by name.
>> [...]
>>> I get this result:
>>> QVariant(Field*)
>>>
>>> I'm not sure if that is correct or not, but I can't explain why the
>>> "name" property of the Field won't evaluate.
>>
>> Hi Paul,
>> The C++-to-script value conversion is based on mapping a string (e.g.
>> "Field*") to a metatype-id, and mapping the metatype-id to a conversion
>> function (installed with qscriptRegisterMetaType()). The built-in types
>> that QtScript can handle are QObject* and QWidget* (see "Conversion
>> Between QtScript and C++ Types" in the docs), so I suggest using those
>> types in your method signatures when designing scripting APIs (just like
>> with the QObject-subclass-type-as-argument issue you encountered
>> before), unless you have special needs for how conversion should be
>> performed for your types.
>>
>> The docs will be updated to be more explicit about this case, because I
>> agree it looks strange from the top-level perspective (that is, even
>> though you subclassed QObject and used the Q_OBJECT macro, it doesn't
>> really matter; all QtScript sees when your Global slot is invoked is a
>> return type identified by the string "Field*" -- there's no more
>> contextual information to go by. That's why you have to tell QtScript
>> what to do in such cases).
>
> Thanks Kent - nice summary. That really explains a lot. I was thrown
> off completely because the docs make it look like
> qScriptRegisterMetaType is only needed for non-QObject types.
>
--
[ signature omitted ]
Message 6 in thread
Peter Hackett wrote:
> In case other might find it helpful, I deal with
> qscriptRegisterMetaType() with
> a template:
Sweet! This is exactly what I needed. Thanks!!
>
> template <typename T,typename BASE=void,bool SCRIPT_OWN = false>
> // ===============
> class IqtScriptHelper
> // ===============
> {
> public:
> typedef T* Tptr;
> static QScriptValue toScriptValue(QScriptEngine* engine,
> const Tptr& fsObj)
> {
> Tptr nonConstFsObj = const_cast<Tptr>(fsObj);
> if ( SCRIPT_OWN ) {
> return engine->newQObject(nonConstFsObj,
> QScriptEngine::ScriptOwnership);
> } else {
> return engine->newQObject(nonConstFsObj);
> }
> }
> static void fromScriptValue(const QScriptValue& scriptValue,
> Tptr& fsObj)
> {
> QObject* qobj = scriptValue.toQObject();
> fsObj = static_cast<Tptr>(qobj);
> }
> // needed these next two versions for FsContainer* (because c++ doesn't
> // know that all "real" FsContainer*s are QObject*s (FsObj*s))
> static QScriptValue toBASEToScriptValue(QScriptEngine* engine,
> const Tptr& pt)
> {
> BASE* fsObj = NULL;
> if ( pt != NULL ) {
> Tptr nonConstPt = const_cast<Tptr>(pt);
> fsObj = dynamic_cast<BASE*>(nonConstPt);
> ICM_ASSERT(fsObj != NULL,"dynamic_cast<BASE*> failed",
> TYPENAME(*nonConstPt));
> }
> if ( SCRIPT_OWN ) {
> return engine->newQObject(fsObj,QScriptEngine::ScriptOwnership);
> } else {
> return engine->newQObject(fsObj);
> }
> }
> static void fromScriptValueToBASE(const QScriptValue&
> scriptValue,
> Tptr& fsObj)
> {
> QObject* qobj = scriptValue.toQObject();
> if ( qobj == NULL ) {
> fsObj = NULL;
> } else {
> fsObj = dynamic_cast<Tptr>(qobj);
> ICM_ASSERT(fsObj != NULL,"dynamic_cast to Tptr failed",
> TYPENAME(*qobj));
> }
> }
> };
>
> And use it like this:
>
> ...
> // FsDir*
> qmetaTy =
> qScriptRegisterMetaType<IqtScriptHelper<FsDir>::Tptr>(
> scriptEngine,
> IqtScriptHelper<FsDir>::toScriptValue,
> IqtScriptHelper<FsDir>::fromScriptValue);
> ...
> // FsContainer*
> qmetaTy =
> qScriptRegisterMetaType<IqtScriptHelper<FsContainer>::Tptr>(
> scriptEngine,
> IqtScriptHelper<FsContainer,FsObj>::toBASEToScriptValue,
> // note ------
> IqtScriptHelper<FsContainer,FsObj>::fromScriptValueToBASE);
> // note ------
> ...
> // FsObjIter*
> qmetaTy =
> qScriptRegisterMetaType<IqtScriptHelper<FsObjIter>::Tptr>(
> scriptEngine,
>
> IqtScriptHelper<FsObjIter,void,/*scriptOwn*/true>::toScriptValue,
> // note -----------------
> IqtScriptHelper<FsObjIter>::fromScriptValue);
> ...
>
>
> Paul Miller wrote:
>> Kent Hansen wrote:
>>> Paul Miller wrote:
>>>> I'm attempting to do something documented in the QtScript reference
>>>> and it's not working. I must not be doing something quite right, or
>>>> maybe it's more complicated than it is described in the manual.
>>>>
>>>> I've exposed a global object ("root") through setProperty() as used in
>>>> the docs. My "root" QObject subclass has a slot:
>>>>
>>>> Field *field(const QString &name) const;
>>>>
>>>> The field() slot looks up a Field (which is derived from QObject, and
>>>> has a "name" property) by name.
>>> [...]
>>>> I get this result:
>>>> QVariant(Field*)
>>>>
>>>> I'm not sure if that is correct or not, but I can't explain why the
>>>> "name" property of the Field won't evaluate.
>>>
>>> Hi Paul,
>>> The C++-to-script value conversion is based on mapping a string (e.g.
>>> "Field*") to a metatype-id, and mapping the metatype-id to a conversion
>>> function (installed with qscriptRegisterMetaType()). The built-in types
>>> that QtScript can handle are QObject* and QWidget* (see "Conversion
>>> Between QtScript and C++ Types" in the docs), so I suggest using those
>>> types in your method signatures when designing scripting APIs (just like
>>> with the QObject-subclass-type-as-argument issue you encountered
>>> before), unless you have special needs for how conversion should be
>>> performed for your types.
>>>
>>> The docs will be updated to be more explicit about this case, because I
>>> agree it looks strange from the top-level perspective (that is, even
>>> though you subclassed QObject and used the Q_OBJECT macro, it doesn't
>>> really matter; all QtScript sees when your Global slot is invoked is a
>>> return type identified by the string "Field*" -- there's no more
>>> contextual information to go by. That's why you have to tell QtScript
>>> what to do in such cases).
>>
>> Thanks Kent - nice summary. That really explains a lot. I was thrown
>> off completely because the docs make it look like
>> qScriptRegisterMetaType is only needed for non-QObject types.
>>
>
--
[ signature omitted ]