PDA

View Full Version : How to register pointer type in qScriptRegisterMetatype?



Sacha_D
24th April 2013, 09:02
Hello.

How to register pointer type in qScriptRegisterMetatype?

h-file.


namespace PFT3 {

class TaskEngine : public QObject {
Q_OBJECT
public:
static const char * TaskEngine::nameInScript;
static const char * TaskEngine::scriptTasksNamespaceName;
void createInQScriptEngine(QScriptEngine &scriptEngine);
};

namespace PFT3_Tasks {

class LIBPFT3SHARED_EXPORT BaseData : public QObject {
Q_OBJECT
};

class BaseDataScriptProto : public QObject, protected QScriptable {
Q_OBJECT
};

}// end of namespace PFT3_Tasks

}//end of PFT3 namespace

Q_DECLARE_METATYPE(PFT3::PFT3_Tasks::BaseData)
Q_DECLARE_METATYPE(PFT3::PFT3_Tasks::BaseData*)
Q_DECLARE_METATYPE(const PFT3::PFT3_Tasks::BaseData*)


cpp-file


QScriptValue PFT3TaskBaseDataToScriptValue(QScriptEngine *engine, PFT3::PFT3_Tasks::BaseData * const &in){
return engine->newQObject(in, QScriptEngine::AutoOwnership);
}

void PFT3TaskBaseDataFromScriptValue(const QScriptValue &object, PFT3::PFT3_Tasks::BaseData * &out){
out = qobject_cast<PFT3::PFT3_Tasks::BaseData*>(object.toQObject());
}

namespace PFT3 {

const char * TaskEngine::nameInScript = "pft3TaskEngine";
const char * TaskEngine::scriptTasksNamespaceName = "PFT3_Tasks";//Changing this name doesn't changes 'PFT3_Tasks::BaseData*' string in error. This is only coincidence.

void TaskEngine::createInQScriptEngine(QScriptEngine &scriptEngine){
/*Create single for given scriptEngine TaskEngine*/
QScriptValue scriptTaskEngineObject = scriptEngine.newQObject(this);
scriptEngine.globalObject().setProperty(nameInScri pt, scriptTaskEngineObject);
/*Adding prototypes*/
QScriptValue scriptTasksNamespace = scriptEngine.newQObject(new QObject(), QScriptEngine::ScriptOwnership);
scriptEngine.globalObject().setProperty(scriptTask sNamespaceName, scriptTasksNamespace);
/*BaseData*/
PFT3_Tasks::BaseDataScriptProto *baseDataPrototypeObject = new PFT3_Tasks::BaseDataScriptProto (&scriptEngine);
const QScriptValue baseDataProto = scriptEngine.newQObject(baseDataPrototypeObject, QScriptEngine::ScriptOwnership);
scriptEngine.setDefaultPrototype(qMetaTypeId<PFT3::PFT3_Tasks::BaseData>(), baseDataProto);
QScriptValue baseDataCtor = scriptEngine.newFunction(&PFT3_Tasks::BaseData::construct, baseDataProto);
scriptEngine.globalObject().property(scriptTasksNa mespaceName).setProperty("BaseData", baseDataCtor);

/*-------------------------------------------------------------------------------------------------------*/
qScriptRegisterMetaType(&scriptEngine, PFT3TaskBaseDataToScriptValue, PFT3TaskBaseDataFromScriptValue);//I register it here.
/*-------------------------------------------------------------------------------------------------------*/

}

}// end of namespace PFT3


Then I write on QtScript:


//delete task;
var task = new PFT3_Tasks.BaseData(1, 2, 6000, 2000, true);
pft3TaskEngine.appendTask(task);

And get script exception,that I parse to output:

Error in script caused the exception:
"TypeError: cannot call appendTask(): argument 1 has unknown type `PFT3_Tasks::BaseData*' (register the type with qScriptRegisterMetaType())"
at executing line 3.
Call stack:
1. <anonymous>()@Script, entered by user:3

http://lists.qt.nokia.com/public/qt-interest/2009-February/002051.html I read and tried with typedef.
Making Applications Scriptable I read too and many times.
How to do this correctly?
Thank you for your replies.

anda_skoa
24th April 2013, 12:22
Couple of points:

1) I would use QScriptEngine::newObject() instead of newQObject() for the namespace

2) I would not use a QObject subclass for the data entry if possible, only the prototype has to be. You can then pass BaseData as value and const reference

3) Since you are using a prototype, you don't need conversion functions and you don't need to call qScriptRegisterMetaType()

You basically do something like this


const int typeId = qRegisterMetaType<PFT3::PFT3_Tasks::BaseData*>("PFT3::PFT3_Tasks::BaseData*");
QScriptValue prototype = engine->newQObject(new PFT3_Tasks::BaseDataScriptProto(engine));
engine->setDefaultPrototype(typeId, prototype);
engine->setDefaultPrototype(qMetaTypeId<PFT3::PFT3_Tasks::BaseData>(), prototype);

QScriptValue namespaceObj = engine->newObject();
engine->globalObject().setProperty("PFT3_Tasks", namespaceObj);

QScriptValue creator = engine->newFunction(createData, prototype);
namespaceObj.setProperty("BaseData", creator);


In functions of the prototype class you then access the data objects like this


qscriptvalue_cast<BaseData*>(thisObject());


The constructor function would look like this


QScriptValue createData(QScriptContext *context, QScriptEngine *engine)
{
if (context->isCalledAsConstructor()) {
BaseData *data = new BaseData;
return engine->toScriptValue(data);
} else {
return engine->undefinedValue();
}
}


Cheers,
_

Sacha_D
24th April 2013, 14:13
Thank you.
I added this 2 lines to my code and it began to work.


const int typeId = qRegisterMetaType<PFT3::PFT3_Tasks::BaseData*>("PFT3_Tasks::BaseData*");
scriptEngine.setDefaultPrototype(typeId, baseDataProto);

But why it shows me the same error if I write like you advised to me?

const int typeId = qRegisterMetaType<PFT3::PFT3_Tasks::BaseData*>("PFT3::PFT3_Tasks::BaseData*");

PFT3_Task is in namespace PFT3.

Same error
"TypeError: cannot call appendTask(): argument 1 has unknown type `PFT3_Tasks::BaseData*' (register the type with qScriptRegisterMetaType())" I have got when BaseData in script was in globalObject direcly before I created this topic.

I want want to understand: "Why it not needs PFT3::"?

anda_skoa
25th April 2013, 15:12
Good question.
Do you have a "using namespace PFT3" clause somewhere?

Maybe try to call qRegisterMetaType without any argument, i.e. only specify the template argument but no value inside the parentheses.

Cheers,
_