【问题标题】:Qt Model-View programming. QAbstractItemModel and QAbstractListModel. index() and parent()Qt 模型视图编程。 QAbstractItemModel 和 QAbstractListModel。索引()和父()
【发布时间】:2014-06-13 17:42:57
【问题描述】:

请帮帮我,我卡住了。

我有一个QList 在 QTreeView 中以特定格式显示的结构。我实际上对显示没有问题;我重新实现了data(),效果很好。

我的数据是“平坦的”,即。 e.每个节点都是一个根元素。此外,不需要从视图中修改数据,即。 e.它是只读的。

我不明白什么是模型索引。它们的正确用途是什么。

目前在data(),我通过模型row (index.row()) 返回了QList 的对应项。这似乎是合法的,这就是 data() 的用途。

除了data(),我还重新实现了rowCount()columnCount()flags()headerData()

对于QAbstractListModel 来说已经足够了,但是要从QAbstractItemModel 继承,我还需要重新实现parent()index()。而且我不知道在这些函数中我到底需要做什么。如果我返回一个空模型索引 (return QModelIndex()),则不会显示任何数据。

我理解 MVC 的理念:视图能够以多种最合适和最有用的方式显示数据。例如,视图可以按字母顺序或任何方式对数据进行排序,因此显示的行的顺序将不同于数据在应用程序内部的组织方式。但我不明白这在我的情况下如何工作,我的应用程序和 Qt 的情况。

视图只是简单地为每一行和每一列查询我的模型的data() 函数,并且因为我拥有的数据没有被修改,例如。 G。排序后,视图总是以相同的顺序显示数据(即使我单击标题对视图进行排序)。我可以自己对列表进行排序,但是我会丢失正确的顺序(例如,应用程序想要获取一个项目#3,但在列表排序之后,需要的项目有另一个数字),这并没有完全不像 MVC:当数据视图发生变化时,数据也会发生变化。不应该。

以上是问题。代码来了。

好吧,我认为不需要代码来说明我的问题,因为我已经写了足够多的字。我实际上有两个问题:我目前从QAbstractListModel 继承,但我想从QAbstractItemModel 继承。所以我需要写index()parent()。我也不明白排序应该如何工作。

不管怎样,我突然用谷歌搜索了this page。它看起来非常接近我所拥有的(除了编辑:我不需要用视图编辑我的数据,所以我没有实现相应的功能;我也显示图片,而不是仅文本(没问题))。我想知道如何使用QAbstractItemModel 做同样的事情(查看该页面)。

如果我不清楚,请告诉我。 :/

【问题讨论】:

  • 你真正想要得到什么样的数据布局?一些节点的列表,其中哪些有一些与您的项目字段相关联的子节点?
  • @Lol4t0 不,我已经在我的帖子中指出了这一点:My data is "flat", i. e. every node is a root element。它基本上是一个字符串列表(几列)的 QList。我使用QTreeView 而不是QListView 只是因为QListView 没有标题。 QListView 的文档说如果我需要一个标题,我应该使用 QTreeView
  • @Lol4t0 我更新了我的评论。这是一个字符串列表的QList,所以我有几列。我也在一些专栏中展示了一些图片,但这不是主题。
  • 哦,我还以为是你目前的情况,你想改变布局。您可以将 ListModel 与 TreeView 一起使用(反之亦然)。模型和视图完全独立。
  • @Lol4t0 你的 ListModel 是什么?我知道我可以从QAbstractListModel 继承。但请重新阅读问题。 :)

标签: c++ qt model-view-controller model qt4


【解决方案1】:

一般来说,如果QAbstractListModelQAbstractTableModel 适合您的任务,您应该使用它而不是QAbstractItemModel。你没有说你为什么要从QAbstractItemModel派生。

但是你的问题还是可以回答的:

  1. 由于您的数据是平坦的,因此您应该始终在 parent() 方法中返回 QModelIndex()

  2. index() 方法中,如果行和列有效,则应返回createIndex(row, column),否则应返回QModelIndex()。您可以使用createIndex 的第三个参数将其他数据附加到索引。

排序是另一个问题。 Qt 建议将数据模型逻辑和排序逻辑分开。您应该有一个包含主要数据的基本模型。这个模型应该完全不知道任何排序。您应该使用QSortFilterProxyModel 对象作为视图的模型,并使用QSortFilterProxyModel::setSourceModel 为排序模型设置数据源模型。代理模型会做所有的排序工作,你只需要告诉它做什么。

【讨论】:

  • 所以你的意思是我现在所做的还可以,我只需要学习排序代理模型?
  • 人们通常在index()的索引上附加什么?我知道我可以不附加任何内容,但我只是询问人们通常将这些额外的存储空间用于什么目的。
  • 嗯嗯,好的,很好,我已经成功从QAbstractItemModel子类化了,谢谢!
  • 但是您能否也回答一下我使用 ModelIndexes 的方式是否正确?
【解决方案2】:

@pavel-strakhov:

index() 方法中,如果行和列有效,则应返回createIndex(row, column),否则应返回QModelIndex()。您可以使用createIndex 的第三个参数将其他数据附加到索引。

这是完全错误的。我已经实现了index(),就像我在上面的答案中被告知的那样,并得到了一棵无限递归的树:每个节点都在其子节点中拥有整棵树。

我什至不需要检查行和列是否有效,视图本身可以很好地利用模型的rowCount()columnCount() 方法。

正确的做法:

QModelIndex HostModel::index(int row,int column,const QModelIndex &parent) const{
    if(!parent.isValid()) // we should return a valid QModelIndex for root elements (whose parent
        return this->createIndex(row,column); // is invalid) only, because our model is flat
    else
        return QModelIndex();
}

我还问过我对 ModelIndexes 所做的一切是否正常。 没有人回答我(即使是答案的作者也有 2 个赞)。不知道为什么。以及为什么一个错误的答案得到了 2 个赞成票,我也不知道。你们让事情变得更糟。

我认为我在data() 中所做的一切都还好。但我不确定,但它现在运行良好。

使用代理对我的模型(对应于 MVC)的请求的 QSortFilterProxyModel(),排序现在可以正常工作(嗯,效果很好)。

P。 S. 非常感谢 @Lol4t0 的帮助:他在 Skype 上私下告诉我应该如何实现 index()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    相关资源
    最近更新 更多