QML: type error with custom QObject
I'm trying to do something in QML to try and make it easier to merge the two more smoothly; to be precise, I am trying to link a structured data object with QML.
I have the following setup:
main.cpp:
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include "dataobject.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qmlRegisterType<DataObject>("DO", 1,0,"DataObject");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
return app.exec();
}
dataobject.h:
#ifndef DATAOBJECT_H
#define DATAOBJECT_H
#include <QObject>
#include <QVariant>
#include <iostream>
class DataObject : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal a MEMBER a NOTIFY aChanged)
Q_PROPERTY(qreal b MEMBER b NOTIFY bChanged)
public:
explicit DataObject(QObject *parent = 0);
signals:
void aChanged();
void bChanged();
public slots:
void printState() {
using namespace std;
cout << a << ", " << b << endl;
}
private:
qreal a;
qreal b;
};
#endif // DATAOBJECT_H
dataobject.cpp:
#include "dataobject.h"
DataObject::DataObject(QObject *parent) :
QObject(parent)
{
connect(this, SIGNAL(aChanged()), this, SLOT(printState()));
connect(this, SIGNAL(bChanged()), this, SLOT(printState()));
}
main.qml:
import DO 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
Text {
text: qsTr("Hello World")
MouseArea {
property DataObject myData;
anchors.fill: parent
drag.target: parent
onReleased: {
myData.a = mouse.x;
myData.b = mouse.y;
}
}
}
}
qml.qrc:
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>
Now I was hoping that the values generated by QML could be directly cast to a C ++ object (i.e. the onReleased handler in MouseArea is trying to write to the myData field). However, this basic proof of concept doesn't work, but I really don't understand why.
The error I am getting (while dragging and releasing the mouse button) is: qrc: ///main.qml: 29: TypeError: Please enter an error
Which matches the line "myData.a = mouse.x;" so it will fire immediately.
Any idea where I am going wrong? I've tried using int, double, QVariant and qreal fields, none of which worked. Is there a fundamental inability in QML to bind such objects? If so, any idea how, for example, anchors.fill is implemented in the Qt source code?
source to share
It helps if you break the expression on the line where the error is coming from. Try to print first myData.a
:
print(myData.a)
myData.a = mouse.x;
myData.b = mouse.y;
qrc: ///main.qml: 31: TypeError: Cannot read property 'a' from null
So myData
- null
. We can check this with another type QObject
:
MouseArea {
property DataObject myData;
property Item item
anchors.fill: parent
drag.target: parent
onReleased: {
print(item)
myData.a = mouse.x;
myData.b = mouse.y;
}
}
qml: null
So, you can fix this error by initializing the property:
property DataObject myData: DataObject {}
You can think of QObject-based properties as JavaScript pointers; they can either be null
pointing to a valid object ... or be undefined
. :) I can't find anything mentioned about this here , but in this case, this behavior should be mentioned.
If you want to simplify things, you can create a default object created for you by making it a child object MouseArea
, not a property:
MouseArea {
DataObject {
id: myData
}
anchors.fill: parent
drag.target: parent
onReleased: {
myData.a = mouse.x;
myData.b = mouse.y;
}
}
You will not be able to reference this property from C ++ at this time. However, you can achieve this in two ways:
- Declare a property alias to this element.
- Give it
objectName
and use QObject :: findChild to find it.
source to share