我通过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
}
}
答案 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。