QML无法将shared_ptr <track />赋值给[未知属性类型]

时间:2013-10-16 11:32:07

标签: c++ qt qml

我通过setContextProperty将shared_ptr<Track>传递给QtQuick2ApplicationViewer。 然后将传递的值(inputStream)分配给PianoRoll的属性,PianoRoll是一个自定义的QQuickItem,它具有类型为shared_ptr<Track>的属性流。

我收到以下错误消息:

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
    }

}

1 个答案:

答案 0 :(得分:3)

shared_ptr(或QSharedPointer)传递给QML几乎没有意义,因此QML引擎不支持它。 QML支持非常有限的数据类型列表。如果您传递指针,它必须是指向QObject的裸指针。

您可以自己管理对象的生命周期,也可以让QML执行此操作。您通过void QQmlEngine::setObjectOwnership(QObject*, ObjectOwnership)声明了您的意图。

如果您想为自己保留对象,请设置CppOwnership。如果您打算将所有权移至QML引擎,请设置JavaScriptOwnership。这就是它的全部内容。无需在任何地方传递智能指针。

以下错误:

  

PianoRollDemo.qml:10:无法将Track *分配给[未知属性类型]

Track*分配给stream的{​​{1}}属性时会发生

。该属性的类型为PianoRoll。再一次,它不可能。它必须是shared_ptr<Track>类型。您放入Track*的类型是外部用户可见的类型,对于QObject,它必须只是Q_PROPERTY。在内部,您可以将其存储在您希望的任何智能指针类型中。

对从Track*派生的类型使用Q_DECLARE_METATYPE也绝对没有意义。当然,您必须在所有QObject* - 派生类型中调用qmlRegisterType来接触QML。