我对qml感到困惑。自几周以来,我尝试在使用QML的视频中实施一个注释内容的时间表,并且我真的无法奏效,因为我是QML的新手。
我试图解决我的问题。这是一个例子,时间表应该是:时间轴示例我得到了不同的曲目,其中我存储了不同的注释,这些注释仅表示,从起点到终点,视频包含给定曲目的注释。例如,如果我注释包含阳光的图像的视频中的所有场景,则每个注释框都标记了视频具有阳光的场景。
我计划通过XML文件保存和获取此信息。一个可能的例子是:
<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>
要将数据放入我以后可以使用的模型中,我用这样的方法解析文件:
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);
}
}
}
,在TrackItem将其带有QLIST的儿童中,带有存储数据的QMAP以及可能是父型TrackItem的QMAP。因此,我的数据比看起来很像没有父对象的树,因为它已经存储了长度和文件名,并且作为其子对象,它具有用于不同轨道的TrackItems。轨道轨迹比将根对象作为父对象,而仅存储曲目的名称。每个曲目都比具有起点和终点为ItemData作为孩子的注释。
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实现。我自己的qabtractiTemModel当前具有以下角色。
rolenames():
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[StartFrameRole] = "startFrame";
roles[EndFrameRole] = "endFrame";
return roles;
数据功能如下。
data(const qmodelIndex&amp; index,int角色):
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();
使用getItem(const qmodelIndex&amp; index):
if (index.isValid()) {
TrackItem *item = static_cast<TrackItem*>(index.internalPointer());
if (item)
return item;
}
return rootItem;
和TrackItem :: data(QString键)返回在TrackItem的QMAP ItemData中存储的数据。
index(int row,int列,const qmodelindex&amp; parent):
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文件,我将其设置在我自己的Qwidget的构造函数中,该文件代表上面的示例的外观。
TimelineWidget构造函数从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上下文的特定属性,因此我可以在QML中使用我的模型。
因此,从本质上讲,我的时间表QML文件是一个包含两个列的矩形。在第一个中,我通过上下文属性" TrackModel"创建了带有轨道名称的轨道头。
Repeater {
id: headerRepeater
model: trackmodel
TrackHead {
label: model.name
width: headerWidth
height: 50
selected: false
}
}
在第二列I中,基本上比在卷轴上创建每个曲目:
Item {
width: tracksContainer.width + headerWidth
height: headers.height + 30
Column {
id: tracksContainer
Repeater {
id: tracksRepeater
model: trackDelegateModel
}
}
}
在这里,我使用了一个授权模型,我尝试在其中构建单个轨道。
DelegateModel {
id: trackDelegateModel
model: trackmodel
Track {
model: trackmodel
trackId: index
height: 50
width: timelineLength
...
also here are some "slots"
}
}
现在到达轨道QML文件。每个曲目也只是一个矩形,我尝试创建新项目,应该代表注释。在这里,我也尝试使用代表。
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"
}
}
因此,在这一点上,我尝试通过启动框架和端框角色从qabstractitemmmmodel获取信息,以计算每个注释的长度。注释不仅仅是另一个矩形,其中有一些操纵可能性将它们移至曲目中的另一个框架或整个曲目中的另一个框架,修剪它们和其他一些东西。
现在终于解决了我的问题。我可以像上面的示例一样构建时间表。示例中的黄色框在gimp中绘制。我无法显示注释,因为我不了解如何创建QmodelIndex。每次我介入QabStractItemModel的数据功能时,我只能在根之后从图层中获取跟踪EM,因此只能从轨道层中获得。Qtquick与QABSTRACTITEMMMMODEL进行了什么方式?我以为我在索引函数中获得了一个行和列,并且可以为每个TrackItem创建唯一的索引,以便我可以在数据功能中使用GetItem函数抓住适当的TrackItem。在索引函数中,某种程度的列始终为0。如何告诉我的模型,我是哪个层(根,轨道或注释),以便在QML中可以获取代表中的正确数据?我希望我的问题足够清楚。这是我在这里的第一篇文章,所以如果长时间或不合格,我可能会道歉。我真的希望有人可以帮助我解决这个问题。
我在重新完成示例"可编辑树模型"时偶然发现了同一问题。我的模型中有2个柱塞。当我单击第二列Selection.currentIndex.Column总是返回0时,styledata.index.column属性也是如此。但是styledata.column在我点击第二列时给了我1个。因此,我在qml中明确构建了我需要的索引。
var currentIndex = myTreeModel.index(styleData.index.row, styleData.column, styleData.index.parent)
var success = myTreeModel.setData( currentIndex , loaderEditor.item.text, 2 )
之后,我得到了我的setData函数来完成它应该做的事情 - 在模型的第二列中更改值。这是一种黑客,但仍然有效。我希望这对某人有用。
P.S。可编辑模型示例之间的唯一重大区别我的实现是,他们正在使用
从C 方面使用该模型 view->setModel(model)
我正在通过qmlregistertype使用我的模型。这是我能想到的唯一区别。