QtScript plus enums

2.1k Views Asked by At

I am adding QScript to my Qt application. I have already added metadata and use some of the metadata functions to interrogate through C++ code. That works fine - I can navigate the object heirarchy and print out values (including enums).

But, I can't seen to get enums working in Qt script.

I have my class...

class HalPin : public QObject
{
Q_OBJECT
public:
enum EHalPinType
{
    Bit = HAL_BIT,
    Float = HAL_FLOAT,
    S32 = HAL_S32,
    U32 = HAL_U32
};

enum EHalPinDirection
{
    In = HAL_IN,
    Out = HAL_OUT,
    IO = HAL_IO
};
Q_ENUMS(EHalPinType)
Q_ENUMS(EHalPinDirection)

public:
explicit HalPin(QObject *parent = 0);

signals:

public slots:

};

Q_DECLARE_METATYPE(HalPin::EHalPinType)
Q_DECLARE_METATYPE(HalPin::EHalPinDirection)
Q_DECLARE_METATYPE(HalPin*)

I have another class that has a method that takes the enums as arguments...

class EmcHal : public QObject
{
Q_OBJECT
public:
explicit EmcHal(QString moduleName, QObject *parent = 0);

signals:

public slots:
QObject *createHalPin( HalPin::EHalPinType, HalPin::EHalPinDirection, QString name );
};

This class is exposed in another class - sorry I should have simplified the example. If I write the following jscript code,

var nextPagePin1 = Emc.hal.createHalPin();

I get an error I expect...

SyntaxError: too few arguments in call to createHalPin(); candidates are createHalPin(HalPin::EHalPinType,HalPin::EHalPinDirection,QString)

So, it appears that the enum types are known to qtscript.

What I am struggling to do is to set the enum arguments from jscript. I've tried many combinations...

Bit
EHalPinType.Bit
HalPin.EHalPinType.Bit

and many more.

If I try to use integers, I get...

TypeError: cannot call createHalPin(): argument 1 has unknown type `HalPin::EHalPinType' (register the type with qScriptRegisterMetaType())

which seems to imply jscript doesn't know about my enums.

Any suggestions?

Do I need to use qRegisterMetaType or qScriptRegisterMetaType to access my enums? The documentation doesn't suggest I need to do this. Do I need to implement the converter functions for the qScriptRegisterMetaType method.

Or is my syntax just wrong for the jscript?

Does someone have a working example?

Thanks, Frank

2

There are 2 best solutions below

0
On

To answer my own question...

Well, not so much an answer to why, but a "meh, this works" example...

As I mentioned above, I wasn't able to get the enums working in both the metadata and jscript at the same time using the qt macros. Even though the enum appeared in qscript (I checked in the browser of the script debugger), it didn't evaluate to the correct integer.

I had to add a QMetaObject for the enum. That gave me the enum items, and correct integer values.

But that still gave me the unknown type error, so I needed to use qScriptRegisterMetaType() to register conversion functions for the types.

This is the class I use for 1 enum. It is as minimal as I can make it. I should be able to use macros to shrink it down a bit more, but there are limitations on what can be macroised, because of the qt moc requirements.

#include <QObject>
#include <QMetaType>
#include <QScriptEngine>

#include "hal.h"


class CEHalPinType : public QObject
{
Q_OBJECT
public:
    explicit CEHalPinType(QObject *parent = 0) : QObject(parent) {}
    explicit CEHalPinType(const CEHalPinType &other) : QObject(other.parent()) {}
    virtual ~CEHalPinType() {}

    enum EHalPinType
    {
        Bit = HAL_BIT,
        Float = HAL_FLOAT,
        S32 = HAL_S32,
        U32 = HAL_U32
    };
    Q_ENUMS( EHalPinType )

private:
    static QScriptValue toScriptValue(QScriptEngine *engine, const EHalPinType &s)
    {
        return engine->newVariant((int)s);
    }

    static void fromScriptValue(const QScriptValue &obj, EHalPinType &s)
    {
        s = (EHalPinType)obj.toInt32();
    }
    static QScriptValue qscriptConstructor( QScriptContext *context, QScriptEngine *engine )
    {
        return engine->newQObject( new CEHalPinType(context->argument(0).toQObject()), QScriptEngine::ScriptOwnership);
    }
public:
    static void Init( const char *name, QScriptEngine *engine )
    {
        qScriptRegisterMetaType(engine, toScriptValue, fromScriptValue);
        QScriptValue metaObject = engine->newQMetaObject( &staticMetaObject, engine->newFunction(qscriptConstructor) );
        engine->globalObject().setProperty( name, metaObject );
    }
};

Q_DECLARE_METATYPE(CEHalPinType::EHalPinType)

And my jscript looks like...

var nextPagePin = Emc.hal.createHalPin(EHalPinType.Bit,EHalPinDirection.In,"nexis.NextPage");
0
On

Oops. I jumped the gun on this one. Although the scripting worked, I broke the ability to convert enums to strings using the qmetaobject data.

And there doesn't seem to be an automatic way of doing it.

The problem is, I moved the enums out of the class where the properties that used the enums were defined. Although the Q_ENUMS and Q_PROPERTY compile, if I use the QMetaProperty to to read an enum, it doesn't work. The QVariant that is returned shows the correct data type, "CEHalPinType::EHalPinType", but it fails the isEnum() test and canConvert(QVariant::String) fails too. This is because when the qmetaobject code goes searching for the enum type, it only looks in the current class and its derived classes. It doesn't search other classes. Which is why it worked when the enum was a member of the class which also had the properties.

My work around, as suggested elsewhere, was to create my own QMap of known enums, storing the string name to qmetaobject mapping. I used a templated base class and used T::staticMetaObject to get the meta object.