QML로 인해 상당히 혼란 스럽습니다. 몇 주 후에 QML로 동영상에 주석을 달기위한 타임 라인을 구현하려고 시도했는데 QML을 처음 접했기 때문에 실제로 작동시키지 못했습니다.QAQualityItemModel with QtQuick : 인덱스의 열은 항상 0입니다.
나는 내 문제를 해결하려고 노력합니다. 이것은 타임 라인이 어떻게 보일 것인가의 예입니다. Timeline example 비디오에 시작점에서 끝점까지 단순히 서로 다른 주석을 저장하는 다른 트랙이 있습니다. 비디오에 주어진 트랙의 주석이 포함되어 있습니다. 예를 들어 맑은 이미지가 포함 된 비디오의 모든 장면에 주석을 달면 모든 주석 상자에 비디오의 맑은 이미지가있는 장면이 표시됩니다.
예를 들어 XML 파일을 통해이 정보를 저장하고 가져올 계획입니다. 가능성이있는 예는 다음과 같습니다
readModelFromXML() :
QFile xmlFile(_filename);
xmlFile.open(QIODevice::ReadOnly);
xml.setDevice(&xmlFile);
TrackItem* root;
while(!xml.atEnd() && !xml.hasError())
{
QXmlStreamReader::TokenType token = xml.readNext();
if(token == QXmlStreamReader::StartDocument)
continue;
if(token == QXmlStreamReader::StartElement)
{
if(xml.name() == "root")
{
QMap<QString, QVariant> itemData;
itemData["length"] = xml.attributes().value("length").toInt();
itemData["filename"] = xml.attributes().value("filename").toString();
root = new TrackItem(itemData);
}
else if(xml.name() == "track")
{
QMap<QString, QVariant> itemData;
itemData["name"] = xml.attributes().value("name").toString();
TrackItem* track = new TrackItem(itemData, root);
root->insertChildren(root->childCount(), track);
}
else if(xml.name() == "annotation")
{
QMap<QString, QVariant> itemData;
itemData["start"] = xml.attributes().value("start").toInt();
itemData["end"] = xml.attributes().value("end").toInt();
TrackItem* parent = root->child(root->childCount() - 1);
TrackItem* annotation = new TrackItem(itemData, parent);
parent->insertChildren(parent->childCount(), annotation);
}
}
}
<root length="800" filename="tralala.mp4">
<track name="sunny">
<annotation start="20" end="50"/>
<annotation start="70" end="120"/>
...
</track>
<track name="cloudy">
...
</track>
</root>
가 나중에 사용할 수있는 모델로 데이터를 얻으려면,이 같은 방법으로 파일을 구문 분석 TrackItem에 자식이있는 QList, 저장된 데이터가있는 QMap 및 상위 형식의 TrackItem이 포함될 수 있습니다. 따라서 내 데이터는 부모가없는 루트 TrackItem 개체가있는 트리와 비슷하게 보이며 길이와 파일 이름이 저장된 데이터로, 하위 개체로는 다른 트랙에 대한 TrackItem이 있습니다. TrackItems는 루트 개체를 부모로 갖고 있으며 트랙 이름 만 저장합니다. 각 트랙에는 startData와 endData가 자식으로 저장된 주석이 있습니다.
TrackItem.h :
public:
explicit TrackItem(QMap<QString, QVariant> &data, TrackItem *parent = 0);
~TrackItem();
some functions for getting childs, inserting childs and so on
private:
QList<TrackItem*> childItems;
QMap<QString, QVariant> itemData;
TrackItem *parentItem;
그래서 지금 우리가 내 문제에 가까워지고 있습니다. 내 QtQuick 뷰에 대한 통신을 위해 자체 QAbstractItemModel 구현을 만들었습니다. 내 자신의 QAbstractItemModel에는 현재 다음과 같은 역할이 있습니다.
roleNames()는 다음과 같이
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[StartFrameRole] = "startFrame";
roles[EndFrameRole] = "endFrame";
return roles;
데이터 기능을 보인다.
데이터 (CONST이 & 인덱스, INT 역할 QModelIndex) :
if (index.isValid()) {
TrackItem *item = static_cast<TrackItem*>(index.internalPointer());
if (item)
return item;
}
return rootItem;
데이터를 반환 TrackItem :: 데이터 (QString 키)의 getItem과
if (!index.isValid())
return QVariant();
TrackItem *item = getItem(index);
if (role == NameRole)
return item->data("name");
else if (role == StartFrameRole)
return item->data("start");
else if (role == EndFrameRole)
return item->data("end");
return QVariant();
을 (CONST는 & 인덱스를 QModelIndex) TrackItem의 QMap itemData에 저장된다.
지수 (INT 행, INT 열, CONST는 & 부모를 QModelIndex) :
if (parent.isValid() && parent.column() != 0)
return QModelIndex();
TrackItem *parentItem = getItem(parent);
TrackItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
그래서 인덱스에 나는 TrackItems의 인덱스를 만들어보십시오.
C++ 측에 훨씬. 이제 QML 코드를 약간 다루고 내 문제를 따라갑니다. 따라서 QML 측면에서 timeline이라는 QML 파일을 가지고 있습니다.이 QML 파일은 위 예제의 모양을 나타내는 자체 QWidget의 생성자에서 설정합니다.당신이 볼 수 있듯이
sharedEngine_ = new QQmlEngine(this);
quickWidget_ = new QQuickWidget(sharedEngine_, this);
QQmlContext *context = quickWidget_->rootContext();
context->setContextProperty("timeline", this);
model_ = new TrackModel(":/resources/example.txt", context);
context->setContextProperty("trackmodel", model_);
quickWidget_->setSource(QUrl::fromLocalFile("qml/timeline.qml"));
ui->layout->addWidget(quickWidget_);
,이 시점에서 나는 또한 현재 QAbstractItemModel를 작성하고 QML 컨텍스트에 CONTECT 특성으로 설정, 그래서 나는 내 모델을 사용할 수 있습니다
TimelineWidget 생성자는 QWidget에서 파생 된 QML.
기본적으로 내 타임 라인 QML 파일은 두 개의 열이 포함 된 사각형입니다. 첫 번째로 위에서 만든 컨텍스트 속성 "trackmodel"을 통해 리피터를 통해 트랙 이름이있는 트랙 헤드를 만듭니다. 두 번째 열에서
Repeater {
id: headerRepeater
model: trackmodel
TrackHead {
label: model.name
width: headerWidth
height: 50
selected: false
}
}
나는 본질적으로있는 ScrollView 내 각 트랙을 만드는 것보다 : 여기
Item {
width: tracksContainer.width + headerWidth
height: headers.height + 30
Column {
id: tracksContainer
Repeater {
id: tracksRepeater
model: trackDelegateModel
}
}
}
내가 개별 트랙을 구축하려고하는 DelegateModel를 사용합니다.
DelegateModel {
id: trackDelegateModel
model: trackmodel
Track {
model: trackmodel
trackId: index
height: 50
width: timelineLength
...
also here are some "slots"
}
}
이제 Track QML 파일을 참조하십시오. 각 트랙은 주석을 나타내는 새 항목을 만들려고하는 사각형이기도합니다. 여기서도 대리인을 사용하려고합니다. 이 DelegateModel와
Item {
Repeater { id: annotationRepeater; model: trackModel }
}
:
DelegateModel {
id: trackModel
Annotation {
myModel: model
trackIndex: trackId
height: 15
width: model.endFrame - model.startFrame
x: model.startFrame
y: 17.5
...
like before here are also some "slots"
}
}
그래서 각 주석의 길이를 계산하기 위해 startFrame 및 EndFrame에 역할을 통해 QAbstractItemModel에서 정보를 잡아하려고이 시점에서. Annotation은 단순히 트랙의 다른 프레임이나 다른 트랙으로 이동시킬 수있는 조작 기능이있는 또 다른 Rectangle이며 트리밍 및 다른 것들을 트리밍합니다.
마침내 내 문제. 위의 예처럼 타임 라인을 만들 수 있습니다. 예제의 노란색 상자는 김프에서 칠해집니다. QModelIndex가 어떻게 생성되는지 이해할 수 없기 때문에 주석을 표시 할 수 없습니다. 매번 QAbstractItemModel의 데이터 함수로 들어갈 때마다 루트 레이어 다음에 트랙 항목 만 가져올 수 있으므로 트랙 레이어 만 사용할 수 있습니다. QtQuick은 QAbstractItemModel과 어떤 식으로 통신합니까? 인덱스 함수에서 행과 열을 가져 와서 각 TrackItem에 대해 고유 한 인덱스를 만들 수 있다고 생각하여 데이터 함수의 getItem 함수를 사용하여 적절한 TrackItem을 가져올 수있었습니다. 인덱스 함수에서 어떻게 든 column은 항상 0입니다. QML에서 델리게이트의 올바른 데이터를 얻을 수 있도록 필자가 만든 모델 (루트, 트랙 또는 주석)을 어떻게 알 수 있습니까? 제 문제가 해결되기를 바랍니다. 여기는 내 첫 번째 게시물이기 때문에 오랫동안 또는 형태가 벗어난다면 사과 할 수 있습니다. 정말 누군가가이 문제로 나를 도울 수 있기를 바랍니다.
귀하의 질문은 형식이 잘되어 있고 많은 정보가 있지만 제목이 잘못되었습니다. 제목이 문제와 더 관련이있는 경우 사람들이 나중에 답변하고 찾기 쉽게합니다. "색인 기능에서 열은 항상 0입니다."이것은 단지 제안 일 뿐이므로 귀하의 게시물은 훌륭합니다. 희망을 얻었을 때 – leparlon
예, 맞습니다 : QML은 모델의 첫 번째 열만 사용합니다. 그러나 트랙 당 하나의 역할을 가진 모델을 제공 할 수 있습니다. 여기에는 데이터가있는 객체가 포함되어 있습니다. 또 다른 아이디어는 열을 재정렬하는 ['ProxyModel'] (http://doc.qt.io/qt-5/qabstractproxymodel.html)을 통해 모델을 전달하는 것이므로 원하는 열을 항상 가질 수 있습니다. 첫 번째가 되라. – derM
QML의 ['TableModel'] (http://doc.qt.io/qt-5/qml-qtquick-controls-tableview.html)조차도 모델의 한 컬럼만을 사용합니다. 뷰 컬럼 당 첫 번째 모델 컬럼에 하나의'role'을 사용합니다. – derM