QML cannot assign shared_ptr <Track> to [unknown property type]

I am passing shared_ptr<Track>

to QtQuick2ApplicationViewer via setContextProperty. The passed value (inputStream) is then assigned to the PianoRoll property, which is a custom QQuickItem that has a property stream of type shared_ptr<Track>

.

The following error message appears:

PianoRollDemo.qml:10: unable to assign shared_ptr<Track> to [unknown property type]

      

main.cpp

Q_DECLARE_METATYPE(shared_ptr<Track>)
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // qmlRegisterType<Track>("Track", 1, 0, "Track");
    qmlRegisterType<PianoRoll>("PianoRoll", 1, 0, "PianoRoll");

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/Diplomarbeit/PianoRollDemo.qml"));
    viewer.showExpanded();

    if (argc >= 2)
    {
        if (strcmp(argv[1],"-readFile") == 0)
        {
            string fileName = argv[2];
            cout << "Reading from file " << fileName << endl;
            GP5Reader reader;
            MainGame mainGame;
            reader.read(mainGame.score, fileName);

            mainGame.playerInputs.push_back(shared_ptr<Track>(new Track(0)));
            mainGame.onPlayerInput(0, shared_ptr<Note>(new Note(295309, 100, 69, 92)));
            mainGame.onPlayerInput(0, shared_ptr<Note>(new Note(295306, 100, 64, 92)));
            mainGame.onPlayerInput(0, shared_ptr<Note>(new Note(295300, 100, 57, 92)));
            mainGame.onPlayerInput(0, shared_ptr<Note>(new Note(295315, 100, 45, 92)));
        }

        else if(strcmp(argv[1],"-listenToMidi") == 0)
        {
            int port = atoi(argv[2]);
            cout << "Listening to port " << port << endl;
            MidiInput* midiIn = new MidiInput();
            midiIn->listen(port);
            viewer.rootContext()->setContextProperty("inputStream", QVariant::fromValue(midiIn->track));
            /*
            QDeclarativeView view;
            QUrl url = QUrl::fromLocalFile("qml/Diplomarbeit/PianoRollDemo.qml");
            bool valid = url.isValid();
            view.setSource(url);
            view.show();
            */
        }
    }
    else
    {
        cout << "No arguments received." << endl;
    }

    #ifdef Q_OS_ANDROID
        GP5Reader reader;
        Score score;
        reader.read(score, "/storage/emulated/0/test.gp5");
    #endif

    return app.exec();
}

      

pianoroll.h

#ifndef PIANOROLL_H
#define PIANOROLL_H

#include <QQuickItem>
#include <QSGGeometry>
#include <QSGFlatColorMaterial>

#include <track.h>


class PianoRoll : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(shared_ptr<Track> stream READ stream WRITE setStream NOTIFY streamChanged)

public:
    PianoRoll(QQuickItem* parent = 0);

    // Get Methods
    shared_ptr<Track> stream() const;

    // Set Methods
    void setStream(shared_ptr<Track> stream);

protected:
    QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data);

private:
    shared_ptr<Track> m_stream;
    QSGGeometry m_geometry;
    QSGFlatColorMaterial m_material;

signals:
    void streamChanged();
};

QML_DECLARE_TYPE(PianoRoll)

#endif // PIANOROLL_H

      

pianoroll.cpp

#include <QQuickItem>
#include <QSGGeometry>
#include <QSGFlatColorMaterial>
#include <QSGGeometryNode>
#include <QSGSimpleRectNode>

#include <iostream>
#include <memory>

#include "pianoroll.h"
#include "note.h"

using namespace std;


PianoRoll::PianoRoll(QQuickItem *parent) :
    QQuickItem(parent),
    m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4),
    m_stream(new Track)
{
    // Important, otherwise the paint method is never called
    setFlag(ItemHasContents);
    m_material.setColor(Qt::red);

    // TODO: remove TestData
    shared_ptr<Note> noteOn1(new Note(0, 500, 70, 100));
    shared_ptr<Note> noteOn2(new Note(500, 500, 40, 100));
    shared_ptr<Note> noteOn3(new Note(1000, 200, 30, 100));
    m_stream->addNote(noteOn1);
    m_stream->addNote(noteOn2);
    m_stream->addNote(noteOn3);
    //m_stream.addNoteEvent(new NoteEvent(700, 700, 70, 100));
}


shared_ptr<Track> PianoRoll::stream() const
{
    return m_stream;
}


void PianoRoll::setStream(shared_ptr<Track> stream)
{
    if (m_stream == stream) return;
    m_stream = stream;
    emit streamChanged();
    update();
}

QSGNode *PianoRoll::updatePaintNode(QSGNode *n, QQuickItem::UpdatePaintNodeData *data)
{
    QSGGeometryNode *node = static_cast<QSGGeometryNode *>(n);
    if (!node)
    {
        node = new QSGSimpleRectNode(boundingRect(), Qt::white);
    }

    node->removeAllChildNodes();

    qreal msPerScreen = 10000;
    qreal pitchesPerScreen = 128;
    qreal x_factor = (qreal) boundingRect().width() / msPerScreen;
    qreal y_factor = (qreal) boundingRect().height() / pitchesPerScreen;

    for (unsigned int i = 0; i < m_stream->notes.size(); i++)
    {
        shared_ptr<Note> note = m_stream->notes.at(i);
        qreal left = boundingRect().left() + note->getTime() * x_factor;
        qreal top = boundingRect().top() + note->getPitch() * y_factor;
        qreal width = note->getDuration() * x_factor;
        qreal height = y_factor;

        QRectF noteRectangle = QRectF(left, top, width, height);
        node->appendChildNode(new QSGSimpleRectNode(noteRectangle, Qt::black));
    }
    return node;

}

      

track.h

#ifndef NOTESTREAM_H
#define NOTESTREAM_H


#include <vector>
#include <memory>

#include <QVariantList>
#include <QQuickView>

#include "note.h"

using namespace std;


class Track : public QObject
{
public:
    void print();

    //TODO: private:
    QList<shared_ptr<Note>> notes;
    int gMInstrument;
    int trackIndex;
    int stringCount;
    vector<int> tuning;

    bool operator==(Track& other) const;

    Track(int trackIndex = -1);
    ~Track();

public slots:
    void addNote(shared_ptr<Note> note);

signals:


};

#endif // NOTESTREAM_H

      

track.cpp

#include <vector>
#include <memory>
#include <iostream>

#include <QMetaType>
/*
#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/QDeclarativeContext>
*/
#include <QQuickView>
#include <QQmlContext>
#include <qqml.h>

#include "track.h"
#include "note.h"


using namespace std;


void Track::print()
{
    for (unsigned int i = 0; i < notes.size(); i++)
    {
        shared_ptr<Note> event = notes.at(i);
        cout << event->getTime() << "  Pitch: " << event->getPitch() << endl;
    }
    cout << notes.size() << " notes" << endl;
}

bool Track::operator==(Track &other) const
{
    return other.notes == this->notes;
}

Track::Track(int trackIndex)
{
    this->trackIndex = trackIndex;
}

Track::~Track()
{
}

void Track::addNote(shared_ptr<Note> note)
{
    //print();
    this->notes.append(note);
    /*
    listElems.append(QVariant::fromValue(new NoteEvent(1, 1, 1, 1)));
    view->rootContext()->setContextProperty("dataModel",QVariant::fromValue(listElems));
    */
}

      

PianoRollDemo.qml

import QtQuick 2.0
import PianoRoll 1.0

Rectangle {
    width: 500
    height: 200


    PianoRoll {
        stream: inputStream
        anchors.fill: parent
    }

}

      

+2


source to share


1 answer


There is little point in porting shared_ptr

(or QSharedPointer

) in QML, so the QML engine does not support it. QML supports a very limited list of data types. If you are passing a pointer, it must be a bare pointer to QObject

.

You can manage the lifetime of an object yourself, or let QML do it. You announce your intention through void QQmlEngine::setObjectOwnership(QObject*, ObjectOwnership)

.

If you want to keep the object to yourself, install CppOwnership

. If you intend to transfer ownership of the QML engine, install JavaScriptOwnership

. It's all there. There is no need to pass smart pointers anywhere.

Next error:



PianoRollDemo.qml: 10: Cannot assign Track * for [unknown property type]

happens when you assign to a Track*

property stream

PianoRoll

. This property is of type shared_ptr<Track>

. Again, this cannot be. He must be type Track*

. The type you put in Q_PROPERTY

is a type visible to external users, and it should be simple for QObjects Track*

. Internally, you can store it in whatever type of smart pointer you want.

It also makes no sense to use Q_DECLARE_METATYPE

for types derived from QObject*

. You must, of course, name qmlRegisterType

for all QObject

QML-exposed types.

+3


source







All Articles