Reputation: 7390
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
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 QObject
s property()
and setProperty()
.
But in your case that is entirely redundant, simply pass the string itself.
Upvotes: 1
Reputation: 244291
As I said in the comments, QML only passes pointers from the QObject
s, 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