Nulik
Nulik

Reputation: 7390

Passing a pointer to QML string property to C++

How do you pass a pointer to string property from QML to C++?

When I attempted to do it the obvious way, I got this error:

qrc:/NewAccount.qml:236: Error: Unknown method parameter type: QString*

Which means, QML engine can't convert new_account.error_string property to C++ when calling save_account (Q_INVOKABLE) method

This is my code in QML:

import myproject.aewm.ethkey 1.0
import myproject.aewm.walletaccount 1.0
...
id: new_account
property EthKey key: EthKey{}
property WalletAccount account: WalletAccount{}
property string error_string: ""
....
if (aewm_obj.save_account(key,account,new_account.error_string)) {
    wallet_accounts_tabbar.currentIndex=0
} else {
    console.log("error occurred:"+new_account.error_string)
}

Where aewm_obj is a C++ type (registered in QML) and save_account is declared in C++ as :

Q_INVOKABLE     bool save_account(EthKey *key, WalletAccount *account, QString *err_str);

The docs say that a (QML) string property is a QString object, and that these types are automatically converted from from C++ and QML . I am passing pointers to my custom QObject-derived classes without any problems after qmlRegisterType() call, so why I can't do the same with strings?

I thought that maybe string pointers are not supported and I tried to add this line:

qRegisterMetaType<QString*>("QString*");

but after this change, the pointer I received at C++ side was 0x0 and I got a segfault.

So, how do you pass pointers to QML string properties from QML to C++ ?

Or, do you think I should register QString class with qmlRegisterType() too? I tried it but I have encountered some compilation issues, so I think it won't compile.

The last solution would be to create a custom object with a QString inside, and send a pointer to it from QML to C++. But, this would be an overkill, if QString exists why not find a way to use it?

Will appreciate very much your comments. I definitely want to use pointers , it is safer than dealing with object ownership when exchanging data between C++ and QML.

Upvotes: 1

Views: 3856

Answers (2)

dtech
dtech

Reputation: 49329

With Qt, the C++ API and the QML API are completely different, and practically incompatible layers. There is a lot of conversion of data back and forth in order to make the whole thing work. And you don't really have control over it when it comes to primitives like strings. So just get that idea out of your head.

If you want to access a particular property of a particular object, you need to pass the object that will be received as a pointer, and the property name, which then you can access via its name string via QObjects property() and setProperty().

But in your case that is entirely redundant, simply pass the string itself.

Upvotes: 1

eyllanesc
eyllanesc

Reputation: 244291

As I said in the comments, QML only passes pointers from the QObjects, and QString is not a QObject.

I think you are giving an incorrect approach to the problem, you could create a property in the object that performs the calculations that have the error message as shown below.

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

class Foo: public QObject{
    Q_OBJECT
    Q_PROPERTY(QString errorMessage READ errorMessage)
public:
    using QObject::QObject;
    Q_INVOKABLE bool process(int a, int b, int res){
        bool status;
        // some operation
        status = (a+b) == res;
        mErrorMessage = status? "": QString("error message: %1 + %2 is different to %3").arg(a).arg(b).arg(res);
        return status;
    }
    QString errorMessage() const{
        return mErrorMessage;
    }

private:
    QString mErrorMessage;
};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qmlRegisterType<Foo>("com.eyllanesc.org", 1, 0, "Foo");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

#include "main.moc"

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4

import com.eyllanesc.org 1.0

Window {
    visible: true
    width: 640
    height: 480

    Foo{ id: foo }

    Row{
        SpinBox{ id: a }
        SpinBox{ id: b }
        SpinBox{ id: c }

        Button{
            text: "process"
            onClicked: {
                var message;
                if(foo.process(a.value, b.value, c.value)){
                    message = "correct"
                    console.log("successful")
                }
                else{
                    message = foo.errorMessage
                    console.log("error is "+ message)
                }
                txt.text = message
            }
        }
        Label{ id: txt }
    }
}

Upvotes: 2

Related Questions