Access to C++-Instance from ECMAScript

Discussion forum for C++ and script developers who are using the QCAD development platform or who are looking to contribute to QCAD (translations, documentation, etc).

Moderator: andrew

Forum rules

Always indicate your operating system and QCAD version.

Attach drawing files, scripts and screenshots.

Post one question per topic.

Post Reply
mink
Active Member
Posts: 30
Joined: Mon Jan 19, 2015 7:20 pm

Access to C++-Instance from ECMAScript

Post by mink » Thu Feb 26, 2015 10:39 am

Hi Andrew,

I'm stuck on a problem where I am obviously missing a point ....
What I want to achieve: Create Objects by C++ as background-Data. Then I want to access data of theese objects with a script to be able to visualize it (by creating drawing objects).

The error message from the script is:

Code: Select all

Uncaught exception at scripts/DACad/DAassignMachineModel/DAassignMachineModel.js:76: TypeError: Result of expression 'this.damachines.getNumberOfMachines' [undefined] is not a function.
The script code is as follows:

Code: Select all

	// set values to Modellist widgets, and prepare sewfield values
	this.globalDACADGlobals = new DACADGlobals();

	this.damachines = this.globalDACADGlobals.getTheMachineModelList();
	qDebug("damachines = ", this.damachines);
	var nMachines = this.damachines.getNumberOfMachines();
	for (var i = 0; i < nMachines; i++)
	{
		var machName = this.daMachines.getMachineName(i);
		this.modelList.addItem(machName);
	}
Here, this.damachines has the same pointer as it has in the C++ counterpart.

The class DACADGlobals iterface is as follows:

Code: Select all

#ifndef DACADGLOBALS_H_
#define DACADGLOBALS_H_

#include <QtCore/qobject.h>
#include <QString>
#include <QSharedPointer>
#include <QDebug>

#include "DAMachineModelVector.h"
// .... some enums without importance 
class DACADGlobals : public QObject
{
Q_OBJECT
public:
	DACADGlobals();
	virtual ~DACADGlobals();
public slots:
	DAMachineModelVector * getTheMachineModelList();
private:
};

Q_DECLARE_METATYPE( DACADGlobals* )


#endif /* DACADGLOBALS_H_ */
And the implementation:

Code: Select all

#include "DACADGlobals.h"

#include "DAMachineModelVector.h"

static DAMachineModelVector *s_pMachineModelList(NULL);

DACADGlobals::DACADGlobals()
: QObject()
{

}

DACADGlobals::~DACADGlobals()
{

}

DAMachineModelVector * DACADGlobals::getTheMachineModelList()
{
	if (s_pMachineModelList == NULL )
	{
		s_pMachineModelList = new DAMachineModelVector();
		s_pMachineModelList->init();
	}
	qDebug("s_pMachineModelList = %08x", s_pMachineModelList);
	return s_pMachineModelList;
}

I try to register this object in the DACADPlugin.cpp in initScriptExtensions:

Code: Select all

void DACADPlugin::initScriptExtensions(QScriptEngine& engine)
{
    // base class QObject:
    QScriptValue dptQObject = engine.defaultPrototype(qMetaTypeId<QObject*>());

	// handle DACADClass
    QScriptValue* protoDACADClass = new QScriptValue(engine.newVariant(qVariantFromValue((DACADClass *)0)));
    protoDACADClass->setPrototype(dptQObject);
    REcmaHelper::registerFunction(&engine, protoDACADClass, DACADPlugin::DACADClassToString, "toString");
    engine.setDefaultPrototype(qMetaTypeId<DACADClass*>(), *protoDACADClass);
    QScriptValue ctorDACADClass = engine.newFunction(DACADPlugin::createDACADClass, *protoDACADClass, 0);
    engine.globalObject().setProperty("DACADClass", ctorDACADClass, QScriptValue::SkipInEnumeration);

    // handle DAMachineModelVector
    QScriptValue* protoMachineModelVector = new QScriptValue(engine.newVariant(qVariantFromValue((DAMachineModelVector *)0)));
    protoMachineModelVector->setPrototype(dptQObject);
    REcmaHelper::registerFunction(&engine, protoMachineModelVector, DACADPlugin::DAMachineModelVectorToString, "toString");
    engine.setDefaultPrototype(qMetaTypeId<DAMachineModelVector*>(), *protoMachineModelVector);
    QScriptValue ctorDAMachineModelVector = engine.newFunction(DACADPlugin::createDAMachineModelVector, *protoMachineModelVector, 0);
    engine.globalObject().setProperty("DAMachineModelVector", ctorDAMachineModelVector, QScriptValue::SkipInEnumeration);

    // handle DACADGlobals
    QScriptValue* protoDACADGlobals = new QScriptValue(engine.newVariant(qVariantFromValue((DACADGlobals *)0)));
    protoDACADGlobals->setPrototype(dptQObject);
    REcmaHelper::registerFunction(&engine, protoDACADGlobals, DACADPlugin::DACADGlobalsToString, "toString");
    engine.setDefaultPrototype(qMetaTypeId<DACADGlobals*>(), *protoDACADGlobals);
    QScriptValue ctorDACADGlobals = engine.newFunction(DACADPlugin::createDACADGlobals, *protoDACADGlobals, 0);
    engine.globalObject().setProperty("DACADGlobals", ctorDACADGlobals, QScriptValue::SkipInEnumeration);
}
(NB: Access to DACADClass functions works fine after creating the Objects with script).
And the functions referenced above in the include file:

Code: Select all

#ifndef DACADPLUGIN_H_
#define DACADPLUGIN_H_

#include <QDebug>
#include <QObject>
#include <QScriptEngine>
#include <QStringList>

#include "RActionAdapter.h"
#include "RDocumentInterface.h"
#include "RGuiAction.h"
#include "RMainWindow.h"
#include "RPluginInterface.h"

#include "DACADClass.h"

#include "DAMachineModel.h"
#include "DAMachineModelVector.h"
#include "DACADGlobals.h"



/*!
 \brief  Brief

 Detailed
 */
class DACADPlugin: public QObject, public RPluginInterface
{
Q_OBJECT
Q_INTERFACES(RPluginInterface)
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "com.duerkopp-adler.plugin")
#endif

public:
DACADPlugin();

virtual bool init();
virtual void uninit(bool);
virtual void postInit(InitStatus status);
virtual void initScriptExtensions(QScriptEngine& engine);
virtual RPluginInfo getPluginInfo();

// Access functions for intermal classes
static QScriptValue createDACADClass(QScriptContext* context, QScriptEngine* engine);
static QScriptValue DACADClassToString(QScriptContext *context, QScriptEngine * /*engine*/);
static DACADClass* getSelfDACADClass(const QString& fName, QScriptContext* context);

static QScriptValue createDAMachineModelVector(QScriptContext* context, QScriptEngine* engine);
static QScriptValue DAMachineModelVectorToString(QScriptContext *context, QScriptEngine* /*engine*/);
static DAMachineModelVector* getSelfDAMachineModelVector(const QString& fName, QScriptContext* context);

static QScriptValue createDAMachineModel(QScriptContext* context, QScriptEngine* engine);
static QScriptValue DAMachineModelToString(QScriptContext *context, QScriptEngine* /*engine*/);
static DAMachineModel* getSelfDAMachineModel(const QString& fName, QScriptContext* context);

static QScriptValue createDACADGlobals(QScriptContext* context, QScriptEngine* engine);
static QScriptValue DACADGlobalsToString(QScriptContext *context, QScriptEngine* /*engine*/);
static DACADGlobals* getSelfDACADGlobals(const QString& fName, QScriptContext* context);

public slots:

protected:
RGuiAction* createDACADAction(const QString &name, int sortOrder,RGuiAction::FactoryFunction factory);

};

#endif /* DACADPLUGIN_H_ */
and implemented :

Code: Select all


QScriptValue DACADPlugin::createDACADGlobals(QScriptContext* context, QScriptEngine* engine)
{
    if (context->thisObject().strictlyEquals(engine->globalObject())) {
        return REcmaHelper::throwError(QString::fromLatin1("DACADGlobals(): Did you forget to construct with 'new'?"), context);
    }

    // constructor without arguments:
    if(context->argumentCount() == 0) {
    	DACADGlobals* cppResult = new DACADGlobals();
        return engine->newQObject(context->thisObject(), cppResult);
    }
    else {
        return REcmaHelper::throwError(QString::fromLatin1("DACADGlobals(): no matching constructor found."), context);
    }
}

QScriptValue DACADPlugin::DACADGlobalsToString(QScriptContext *context, QScriptEngine* /*engine*/)
{
	DACADGlobals* self = getSelfDACADGlobals("toString", context);
    return QScriptValue(QString("DACADGlobals(0x%1)").arg((unsigned long int)self, 0, 16));
}

DACADGlobals* DACADPlugin::getSelfDACADGlobals(const QString& fName, QScriptContext* context)
{
	DACADGlobals* self = REcmaHelper::scriptValueTo<DACADGlobals >(context->thisObject());
    if (self == NULL){
        if (fName!="toString") {
            REcmaHelper::throwError(QString("DACADGlobals.%1(): This object is not a DACADGlobals").arg(fName), context);
        }
        return NULL;
    }

    return self;
}
Do you have an idea what I'm missing?
(As you can see, my knowledge of Qt is VERY limited ...)

Regards,
Ulrich
PS: if you need, I can mail the complete sources! Please let me know!

Post Reply

Return to “QCAD Programming, Script Programming and Contributing”