QQmlComponent::Error "Type xxx cannot declare new members."
-
Hi!
I have an old Qt5 QML application that I am trying to port to Qt6. I have managed to get most things up an running. But now I am faced with an error message I do not understand.
I create Qml components from C++. Most work, but not the ones that have a QML type called Body. Body is one of several Qml-types that are based on a custom C++ class and then registered to QML with qmlRegisterType() at application initialization. This registration works without any errors.
The code fails during one of my asserts later in the initialization process. Here:
blockComponent.reset(new QQmlComponent(getViewer()->engine(), Util::getUrlPathToActor("Block.qml"))); //Debug code if (blockComponent->status() != QQmlComponent::Ready) { qDebug() << "Error loading Block component. status: " << blockComponent->status() << " Error: " << blockComponent->errorString(); } //End of debug code //TO FIX: Uncomment the asserts and make sure block.qml works as intended with Body Q_ASSERT_X(blockComponent.get()->status() == QQmlComponent::Ready, "Engine::init()", "Error loading block component");
The errorString() from blockComponent is Type 'Body' cannot declare new members.
blockComponent is of type std::unique_ptr<QQmlComponent>.Here are relevant parts of the body.h that shows the implementation of Qt properties etc. The code will fail even when I comment out all the Q_PROPERTY.
#ifndef BODY_H #define BODY_H #include <QObject> #include "actor.h" #include <memory> #include <qtmetamacros.h> #include "box2dutil.h" Q_MOC_INCLUDE("C:\Users\berge\Documents\QtProjects\carbon-tower\b2Body.h") class b2BodyDef; class Body : public QObject { Q_OBJECT public: //Qt 6 port, changed depreceated Q_ENUMS with Q_ENUM enum BodyType { StaticBody = 0, KinematicBody, DynamicBody }; Q_ENUM(BodyType) enum BodyShape { Rectangle = 0, Circle }; Q_ENUM(BodyShape) explicit Body(QObject *parent = 0); ~Body(); Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) //Responsible for translating QPointF in Scene coordinates to b2vec in b2World coordinates //The position are passed on to the wrapped b2Body. //note: During the physics simulation Box2D can change this property without a signal being emitted. Q_PROPERTY(QPointF position READ position WRITE setPosition NOTIFY setPositionChanged) Q_PROPERTY(Actor* actor READ actor) Q_PROPERTY(qreal density READ density WRITE setDensity NOTIFY densityChanged) Q_PROPERTY(qreal friction READ friction WRITE setFriction NOTIFY frictionChanged) Q_PROPERTY(qreal gravityScale READ gravityScale WRITE setGravityScale NOTIFY gravityScaleChanged) Q_PROPERTY(bool sensor READ sensor WRITE setSensor NOTIFY sensorChanged) Q_PROPERTY(qreal windFactor READ windFactor WRITE setWindFactor NOTIFY windFactorChanged) Q_PROPERTY(Body::BodyType bodyType READ bodyType WRITE setBodyType NOTIFY bodyTypeChanged) Q_PROPERTY(b2Body* body READ body NOTIFY bodyChanged) Q_PROPERTY(int filterCategory READ filterCategory WRITE setFilterCategory NOTIFY filterCategoryChanged) Q_PROPERTY(int filterMask READ filterMask WRITE setFilterMask NOTIFY filterMaskChanged) Q_PROPERTY(bool fixedRotation READ fixedRotation WRITE setFixedRotation NOTIFY fixedRotationChanged) Q_PROPERTY(QPointF linearVelocity READ linearVelocity WRITE setLinearVelocity NOTIFY linearVelocityChanged) Q_PROPERTY(qreal angularVelocity READ angularVelocity WRITE setAngularVelocity NOTIFY angularVelocityChanged) Q_PROPERTY(Body::BodyShape bodyShape READ bodyShape WRITE setBodyShape NOTIFY bodyShapeChanged) Q_INVOKABLE void setTransform(const QPointF& position, float32 angle); Q_INVOKABLE void applyForceToCenter(const QPointF& force);
What is causing this error? This driving me nuts.
-
Okay I think I might have found at least some clues to where the error comes from. It's probably because Qt is unable to create a property cache for the type. See this code snippet from qqmlpropertycachecreator_p.h
But I don't really understand when Qt is unable to create a property cache. Is it only the Q_PROPERTY's that are at fault? But if so, why does it not work even when I comment out all properties?
template <typename ObjectContainer> inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const { if (context.instantiatingProperty) { return context.instantiatingPropertyCache(); } else if (obj->inheritedTypeNameIndex != 0) { auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); if (typeRef->isFullyDynamicType()) { if (obj->propertyCount() > 0 || obj->aliasCount() > 0) { *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties.")); return nullptr; } if (obj->signalCount() > 0) { *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals.")); return nullptr; } if (obj->functionCount() > 0) { *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions.")); return nullptr; } } if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache()) return propertyCache; *error = qQmlCompileError( obj->location, QQmlPropertyCacheCreatorBase::tr("Type '%1' cannot declare new members.") .arg(stringAt(obj->inheritedTypeNameIndex))); return nullptr; } else if (const QV4::CompiledData::Binding *binding = context.instantiatingBinding) { if (binding->isAttachedProperty()) { auto *typeRef = objectContainer->resolvedType( binding->propertyNameIndex); Q_ASSERT(typeRef); QQmlType qmltype = typeRef->type(); if (!qmltype.isValid()) { imports->resolveType( typeLoader, stringAt(binding->propertyNameIndex), &qmltype, nullptr, nullptr); } const QMetaObject *attachedMo = qmltype.attachedPropertiesType(typeLoader); if (!attachedMo) { *error = qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object")); return nullptr; } return QQmlMetaType::propertyCache(attachedMo); } } return nullptr; }
-
I found a solution to my own problem. The problem was actually not the class Body, but another class that is a parent to Body in the qml-file. I had a forward declared class here that I had missed. This used to work in Qt5 but now in Qt6 they have to be replaced with Q_MOC_INCLUDE.
-