4

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(????)
        }
    }   
}
1
  • As a general rule, set context properties BEFORE loading QML. Context properties must be set before loading QML that references the context properties. It still can work but you can incur in strange bugs due to that. Commented Feb 7, 2017 at 23:04

2 Answers 2

1

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>();
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for your answer. I'm getting the following error as i change the code as u mentioned: "Error: Unknown method return type: Foo". What did i miss?
Is this a compiler error or from the QML environment?
It comes from the qml environment as I call the createFoo function.
Ah, it also needs qRegisterMetaType() for Foo. will ammend the answer
Yes that was the problem. Thanks! Is there a good resource that covers that topic in detail? I would like to see a good example of how to integrate c++ in QML.
|
1

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

2 Comments

But i want to dynamically create Foo objects not just a predefined amount. Or can i always use the same? And if i do like u said i get following error: "Error: Unknown method parameter type: Foo"
@Matthias It's really difficult to help since it is not clear the lifetime you want to give to these objects. "Can I always use the same" has only an answer: "it really depends on what you want to achieve". But that's something we can not easily infer here. Generally speaking, you can generate instances dynamically by following the documentation here or maybe by using an Instantiator.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.