Question

I understand how to expose simple data members by creating a new QObject class that has my class as a member. For example:

class MyClass {
public:
    int anInt;
};

And the wrapper

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;
};

But how do I wrap objects with pointer data members? Say for instance I had a linked list class, and wanted to expose it to qml:

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

I can't use the same approach as above, because then the property of the wrapper would be a pointer to LinkedList, not to LinkedListQWrapped. If the list is changed by non-Qt code, I have no way of knowing which (if any) LinkedListQWrapped object correspond to a given LinkedList*.

Now, I'm allowed to change the c++ model, but I can't let it depend on Qt. I can think of one solution where I add a void* user data member to the c++ class and then set it to point to the corresponding wrapped object once I've created the wrapper.

I've seen this sort of thing done in box2d.

Is this a recommended way to solve the problem? Is it common to provide void* user data members in library code to make them play nice with various frameworks such as Qt? Or is there another solution to this problem?

Was it helpful?

Solution

I don't believe you can expose a non-QObject derived classes to QML as the only way I'm aware of is through QQmlContext.

Looking at the QML box2d extentsion it appears all the QML facing classes are derived from QObject in one way or another, take a look here box2d repo.

That said they do use wrapper functions to convert between QML box2d types and regular non-QObject types. i.e.

/**
 * Convenience function to get the Box2DJoint wrapping a b2Joint.
 */
inline Box2DJoint *toBox2DJoint(b2Joint *joint)
{
     return static_cast<Box2DJoint*>(joint->GetUserData());
}

OTHER TIPS

I have just asked a similar Questions: How to expose C++ structs for computations to Qml

It turned out, that there is no direct way. But if you look at the answear to that question, you will see, how we solved it. We simply built a wrapper and made all relevant objects member of it. These member have their own properties, which they just forward via the wrapper.. Then you just have to manage the getter and setter to pass the values to the wrapper's members. For emitting objects from the members, you can introduce EmitterHelperObjects (just small objects, that inherit QObject and whose only task is to throw signals). In some cases, you may need to register the pointer of the wrapper as MetaType. I haven't figured that out, for when I need to do that and when not.

So to sum the approach up: You do not use the pointer directly, but access only their member's properties by using the Wrapper as "Property forwarder". Its a bit of typing, but works out quite well. Personally, I dislike this side of Qt / Qml, this one Object one Identity stuff turns out to be ugly at some situations.

I know you have asked quite a while ago, but maybe it helps others.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top