Qt: Q_PROPERTY с указателем и предварительным объявлением для доступа к QtScript - PullRequest
5 голосов
/ 05 августа 2011

Проблема

Я делаю проект, используя Q_OBJECT и Q_PROPERTY для доступа к некоторым объектам из скриптов.У меня есть две проблемы:

  1. создание классов, использующих предварительные объявления с возможностью сценариев
  2. возвращение свойства в качестве указателя

Пояснения

1.Почему прямое объявление?

Класс B получает прямое объявление A, потому что A требует полный тип B в заголовке из-за шаблонов.В заголовке B необходим только неполный тип (A *), поэтому прямое объявление является действительным.

2.Зачем возвращать указатель?

Мы не можем вернуть копию, так как нам нужен доступ к реальному объекту в скрипте.Мы не можем вернуть ссылку, так как Qt не позволяет слотам возвращать ссылки - их тип будет игнорироваться, они будут возвращать только void *.

Код

Полный кодскачать на pastebin или в виде ZIP-архива или в виде ZIP-архива из доступен минимальный пример , для тестирования / воспроизведения: мне нужно было разделить файлы для пересылкидекларация и для МОС.Я добавил Makefile, чтобы проверить это.Сделайте deps: g ++, moc, Qt.

Важные части

class A; // forward declaration necessary, see explanation above

class B : public QObject {
    Q_OBJECT
    Q_PROPERTY(A a READ GetA) // <-- ERROR HERE
    // ...

public slots:
    A* GetA() { 
        return mA; 
    }

private:
    A* mA;
    // ...
}

Строка ошибки в скрипте:

print(bObj.GetA().GetName());

Ошибка компиляции

Эта ошибка исчезает, когда я закомментирую Q_PROPERTY выше.

tmp/B.moc.hpp:95:51: error: invalid use of incomplete type ‘struct A’
tmp/../B.hpp:10:7: error: forward declaration of ‘struct A’

Исключение скрипта

Когда я опускаю Q_PROPERTY и вызываю метод GetA () как слот из скрипта, я получаюследующее исключение:

Line 7: "TypeError: cannot call GetA(): unknown return type `A*' 
        (register the type with qScriptRegisterMetaType())"

При регистрации A * с помощью qRegisterMetaType<A*>("A*"); это изменяется на:

Line 7: "TypeError: Result of expression 'bObj.GetA().GetName' 
        [undefined] is not a function." 

Это показывает, что GetA () не возвращает объект A или каким-то образом возвращаетуказатель, но скрипт не может разыменовать его.Затем GetA () фактически возвращает QVariant(A*), можно ли это как-то использовать?

Вопросы:

  1. Могу ли я как-то сделать Q_PROPERTY из неполного типа, или как мне избежатьпредварительное объявление?
  2. Могу ли я вернуть ссылку в слот (возможно, некоторые хитрости, например, класс, который оборачивает указатель и «переопределяет» скрипт operator., если что-то подобное существует) или
  3. Можно ли как-то разыменовать QVariant (A *) в A в QtScript?

1 Ответ

6 голосов
/ 06 августа 2011
  1. Тип вашей собственности A, а не A*, поэтому вы получаете очень разумную ошибку.
  2. Вы должны использовать QScriptValue.Посмотри этот код.Хорошо работает:

    class A; // forward declaration necessary, see explanation above
    
    class B : public QObject
    {
        Q_OBJECT
    
        // Using QScriptValue, made from A instead of A to allow script work correctly with an object
        Q_PROPERTY(QScriptValue a READ GetA) 
    
    public slots:
        QScriptValue GetA() {
            //making QScriptValue from A. Type conversion in C style only due to limitation of incomplete type
            //In real app it's beter to put defenition of this slot after A's defenition
            return static_cast<QScriptEngine*>(parent())->newQObject((QObject*)mA);
        }
    
    private:
        A* mA;
        // ...
    public:
        //I decided my object will be a child of scriptEngine, but you can take a pointer to it in some other way
        B(QScriptEngine * parent);
    };
    
    class A: public QObject
    {
        Q_OBJECT
    public slots:
        QString GetName() const {return "a name";}
    public:
        A(QScriptEngine*parent):QObject(parent){}
    
    };
    
    B::B(QScriptEngine *parent):QObject(parent), mA(new A(parent)){}
    
...