2010-08-26

QtScript: небольшая заметка о маленьких биндингах

Иногда возникают ситуации, когда надо иметь доступ из QtScript'а к уже созданным C++-объектам и их методам, но не хочется ни писать громоздкие биндинги, ни менять сигнатуры методов, преобразуя их у QObject'у. К примеру, у нас есть фабрика, которая возвращает уже созданные объекты, но менять возвращаемые типы на QObject не хочется.

В таких случаях можно немного дописать классы, экземпляры которых нам надо использовать в скриптах.
Нам надо добавить три метода:

private:
    static QScriptValue toScriptValue(
            QScriptEngine *engine, 
            TestScriptableClass * const &in);
    static void fromScriptValue(
            const QScriptValue &value, 
            TestScriptableClass *&out);
    static void initializeBinding(QScriptEngine *engine);


Первый будет преобразовывать экземпляр этого класса в QScriptValue, второй наоборот (эти два метода должны быть хорошо знакомы всем, кто работал с биндингами в QtScript), третий же просто добавляет информацию о нашем классе.

.cpp:
Q_DECLARE_METATYPE(TestScriptableClass *)

TestScriptableClass::TestScriptableClass(QObject *parent) :
    QObject(parent)
{
    initializeBinding(
            ApplicationGlobalFactory::getScriptEngine());
}

QScriptValue TestScriptableClass::toScriptValue(
        QScriptEngine *engine, 
        TestScriptableClass * const &in)
{
    return engine->newQObject(in, 
                      QScriptEngine::QtOwnership, 
                      QScriptEngine::PreferExistingWrapperObject);
}

void TestScriptableClass::fromScriptValue(
        const QScriptValue &value, 
        TestScriptableClass *&out)
{
    out = qobject_cast<TestScriptableClass*>(value.toQObject());
}


void TestScriptableClass::initializeBinding(
        QScriptEngine *engine)
{
    static bool isBindingNeeded = true;
    if (!isBindingNeeded)
        return;
    isBindingNeeded = false;
    qScriptRegisterMetaType<TestScriptableClass *>(engine, 
                       TestScriptableClass::toScriptValue, 
                       TestScriptableClass::fromScriptValue, 
                       engine->newVariant(qVariantFromValue(
                               (TestScriptableClass *)0))
                       );
}

Здесь мы просто в конструкторе вызываем initializeBinding(), который регистрирует наш класс в случае первого запуска и ничего не делает при повторных запусках.

Теперь мы можем получать экземпляры этого класса без преобразования к QObject, а напрямую, и из скриптов будут доступны все слоты и методы, помеченные Q_INVOKABLE.

Комментариев нет:

Отправить комментарий