QtScript плюс перечисления
Я добавляю QScript в свое приложение Qt. Я уже добавил метаданные и использую некоторые функции метаданных для опроса кода C++. Это прекрасно работает - я могу перемещаться по иерархии объектов и выводить значения (включая перечисления).
Но я не вижу, чтобы перечисления работали в скрипте Qt.
У меня есть свой класс...
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*)
У меня есть другой класс, который имеет метод, который принимает перечисления в качестве аргументов...
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 );
};
Этот класс представлен в другом классе - извините, я должен был упростить пример. Если я напишу следующий код jscript,
var nextPagePin1 = Emc.hal.createHalPin();
Я получаю сообщение об ошибке...
SyntaxError: too few arguments in call to createHalPin(); candidates are createHalPin(HalPin::EHalPinType,HalPin::EHalPinDirection,QString)
Итак, похоже, что типы перечислений известны qtscript.
Что я пытаюсь сделать, это установить аргументы enum из jscript. Я перепробовал много комбинаций...
Bit
EHalPinType.Bit
HalPin.EHalPinType.Bit
и многое другое.
Если я пытаюсь использовать целые числа, я получаю...
TypeError: cannot call createHalPin(): argument 1 has unknown type `HalPin::EHalPinType' (register the type with qScriptRegisterMetaType())
что подразумевает, что jscript не знает о моих перечислениях.
Какие-либо предложения?
Нужно ли использовать qRegisterMetaType или qScriptRegisterMetaType для доступа к моим перечислениям? Документация не предполагает, что мне нужно это сделать. Нужно ли реализовывать функции конвертера для метода qScriptRegisterMetaType.
Или мой синтаксис просто неправильно для jscript?
У кого-нибудь есть рабочий пример?
Спасибо фрэнк
2 ответа
Чтобы ответить на мой собственный вопрос...
Ну, не столько ответ на вопрос, а пример "это работает"...
Как я упоминал выше, я не смог заставить работать перечисления в метаданных и jscript одновременно с использованием макросов qt. Несмотря на то, что перечисление появилось в qscript (я проверил в браузере отладчика скриптов), оно не получило правильное целое число.
Мне пришлось добавить QMetaObject для перечисления. Это дало мне элементы enum и правильные целочисленные значения.
Но это все равно дало мне неизвестную ошибку типа, поэтому мне нужно было использовать qScriptRegisterMetaType() для регистрации функций преобразования для типов.
Это класс, который я использую для 1 перечисления. Это настолько минимально, насколько я могу это сделать. Я должен быть в состоянии использовать макросы, чтобы уменьшить его немного больше, но есть ограничения на то, что можно макросизировать, из-за требований qt moc.
#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)
И мой jscript выглядит так...
var nextPagePin = Emc.hal.createHalPin(EHalPinType.Bit,EHalPinDirection.In,"nexis.NextPage");
К сожалению. Я бросил пистолет на этом. Хотя сценарии работали, я отказался от возможности преобразовывать перечисления в строки с использованием данных qmetaobject.
И, кажется, нет автоматического способа сделать это.
Проблема в том, что я переместил перечисления из класса, где были определены свойства, которые использовали перечисления. Хотя Q_ENUMS и Q_PROPERTY компилируются, если я использую QMetaProperty для чтения перечисления, это не работает. Возвращаемый QVariant показывает правильный тип данных "CEHalPinType::EHalPinType", но он не проходит тест isEnum(), а canConvert(QVariant::String) тоже не выполняется. Это связано с тем, что когда код qmetaobject отправляется на поиск типа enum, он ищет только текущий класс и его производные классы. Он не ищет другие классы. Вот почему это сработало, когда enum был членом класса, который также имел свойства.
Моя работа вокруг, как предлагалось в другом месте, состояла в том, чтобы создать мой собственный QMap известных перечислений, сохраняя имя строки в отображении qmetaobject. Я использовал шаблонный базовый класс и использовал T::staticMetaObject, чтобы получить мета-объект.