Matthias
Matthias

Reputation: 43

Passing custom c++ type as QML function parameter

Im trying to create and pass a custom class instance to a Q_INVOKABLE function with the respective parameter. I tried to make an example to point out what im trying to do. So basically i have a class Foo and another class Bar with a function that takes Foo as a parameter. I want to call this function in QML but i don't know how to instantiate Foo to pass it as the parameter for that function.

EDIT - More information about the main goal:

The real goal is to have a subclassed QAbstractItemModel that has a list of a custom class objects. That list will then be represented using the models data() function. The model should be represented some how as a view in QML. Also i want to populate the model at runtime. So the model class should have a function that takes a custom class instance and appends it to the internal list. So my approach was to create and pass the custom class instance within qml. I haven't found any example to do that kind of taks. Here is what i've got:

Foo.h

class Foo : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ getName WRITE setName)
public:
    Foo(QString fooName, QObject *parent = 0) : QObject(parent){
        name = fooName;
    }          
    QString getName() const {
        return name;
    }
    void setName(const QString &value){
        name = value;
    }    
private:
    QString name;
};

Bar.h

class Bar : public QObject
{
    Q_OBJECT
public:
    explicit Bar(QObject *parent = 0) : QObject(parent){}

    Q_INVOKABLE void addFoo(const Foo &foo){
        fooList.append(foo);
    } 
private:
    QList<Foo> fooList;
};

main.cpp

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    qmlRegisterType<Foo>("Test", 1, 0, "Foo");
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    engine.rootContext()->setContextProperty("bar", new Bar());    
    return app.exec();
}

main.qml

import Test 1.0

Window {    
    Button {
        id: addFoo
        text: "Add new Foo to Bar"
        onClicked: {
            bar.addFoo(????)
        }
    }   
}

Upvotes: 4

Views: 4822

Answers (2)

Kevin Krammer
Kevin Krammer

Reputation: 5207

You either make Foo instantiable, by giving it a constructor that can be called without arguments, and then use the approach suggested by CMLDMR or you add a "factory" function that can create instances.

In the latter case you either need to work with Foo* as the return value of the factory function and the argument of addFoo() or you change Foo to be a value class with the Q_GADGET macro for properties instead of deriving from QObject

Given that you have no signals in Foo I would recommend the latter.

Roughly like this:

class Foo
{
    Q_GADGET
    Q_PROPERTY(...)

// ....
};


class Bar : public QObject
{
// ...

    Q_INVOKABLE Foo createFoo(const QString &name);
    Q_INVOKABLE void addFoo(const Foo &foo);
};

Edit: it also requires

qRegisterMetaType<Foo>();

Upvotes: 1

CMLDMR
CMLDMR

Reputation: 344

you should create a object by Foo before passing object in QML. Source: Qt5 C++ GUI Programming Cookbook. Lee Zhi Eng, page:37

import Test 1.0

Window {
    Foo {
    id: Foo_object
    }    
    Button {
        id: addFoo
        text: "Add new Foo to Bar"
        onClicked: {
            bar.addFoo(Foo_object)
        }
    }   
}

Upvotes: 1

Related Questions