Как предоставить QML класс, отличный от QObject, с членами-указателями?

Я понимаю, как предоставлять простые элементы данных, создавая новый класс QObject, членом которого является мой класс. Например:

class MyClass {
public:
    int anInt;
};

И обертка

class MyClassQWrapped : public QObject {
    Q_OBJECT
    Q_PROPERTY(int anInt READ anInt write setAnInt NOTIFY anIntChanged)
public:
    int anInt(){return myClass.anInt;}
    void setAnInt(int value){
        if(myClass.anInt==value)return;
        myClass.anInt = value;
        emit anIntChanged;
    }
signals:
    anIntChanged();
private:
    MyClass myClass;
};

Но как мне обернуть объекты элементами данных указателя? Скажем, например, у меня был класс связанного списка, и я хотел открыть его для qml:

Class LinkedList {
public:
    int anInt;
    LinkedList *next;
};

Я не могу использовать тот же подход, что и выше, потому что тогда свойство обертки будет указателем на LinkedList, а не на LinkedListQWrapped. Если список изменен кодом, отличным от Qt, у меня нет возможности узнать, какой (если есть) объект LinkedListQWrapped соответствует данному LinkedList*.

Теперь мне разрешено изменять модель C++, но я не могу допустить, чтобы она зависела от Qt. Я могу придумать одно решение, в котором я добавляю элемент пользовательских данных void* в класс c++, а затем устанавливаю его так, чтобы он указывал на соответствующий обернутый объект после создания оболочки.

Я видел подобное в box2d.

Это рекомендуемый способ решения проблемы? Распространено ли предоставлять void* пользовательских элементов данных в коде библиотеки, чтобы они хорошо работали с различными фреймворками, такими как Qt? Или есть другое решение этой проблемы?


person bobbaluba    schedule 07.02.2014    source источник


Ответы (2)


Я не верю, что вы можете предоставить производные классы, отличные от QObject, для QML, поскольку единственный известный мне способ - через QQmlContext.

Глядя на расширение QML box2d, кажется, что все классы, обращенные к QML, так или иначе являются производными от QObject, посмотрите здесь репозиторий box2d.

Тем не менее, они используют функции-оболочки для преобразования между типами QML box2d и обычными типами, отличными от QObject. то есть

/**
 * Convenience function to get the Box2DJoint wrapping a b2Joint.
 */
inline Box2DJoint *toBox2DJoint(b2Joint *joint)
{
     return static_cast<Box2DJoint*>(joint->GetUserData());
}
person Matthew    schedule 07.02.2014
comment
Ах, здорово! Не знал, что для box2d есть расширение QML. Я, наверное, так и поступлю. Это будет приятно использовать в качестве ссылки. - person bobbaluba; 08.02.2014

Я только что задал похожие вопросы: Как выставить структуры С++ для вычисления в Qml

Оказалось, что прямого пути нет. Но если вы посмотрите на ответ на этот вопрос, то увидите, как мы его решили. Мы просто создали оболочку и сделали ее членами все соответствующие объекты. У этих членов есть свои собственные свойства, которые они просто пересылают через оболочку. Затем вам просто нужно управлять геттером и сеттером, чтобы передать значения членам обертки. Для испускания объектов из членов вы можете ввести EmitterHelperObjects (просто небольшие объекты, которые наследуют QObject и единственной задачей которых является подача сигналов). В некоторых случаях может потребоваться зарегистрировать указатель оболочки как MetaType. Я не понял, когда мне нужно это делать, а когда нет.

Итак, чтобы подвести итог подходу: вы не используете указатель напрямую, а получаете доступ только к свойствам своего члена, используя оболочку в качестве «переадресатора свойств». Это немного печатать, но работает довольно хорошо. Лично мне не нравится эта сторона Qt/Qml, этот один объект Identity в некоторых ситуациях оказывается уродливым.

Я знаю, что вы спрашивали довольно давно, но, возможно, это поможет другим.

person MattW    schedule 20.10.2014
comment
Прошло некоторое время, но я уверен, что именно так я и решил это. Как вы сказали, это много утомительного письма, но это работает довольно хорошо. - person bobbaluba; 21.10.2014