Qt 模型/视图:如何正确处理底层数据
Posted
技术标签:
【中文标题】Qt 模型/视图:如何正确处理底层数据【英文标题】:Qt Model/View: how to handle underlying data properly 【发布时间】:2015-10-13 15:08:40 【问题描述】:我观看了大量视频,并花了很多时间阅读有关模型的论文,如何使用它们,总体思路非常清楚。但是,我仍然没有得到真正让我慢下来的几件事。
我意识到模型只能作为视图和数据之间的接口。但是,当我查看示例代码时,大多数时候,某种数据结构被发送到模型,模型中的所有函数都使用该内部模型数据结构来执行所需的事情:评估标题、行数等。这样的例子构造函数(在这种情况下内部模型 QList 是addressBook
):
AddressbookModel::AddressbookModel(const QString& addresses,
QObject *parent): QAbstractTableModel(parent)
QStringList records = addresses.split(’\n’);
QStringList line;
foreach(QString record, records)
addressBook.append(splitCSVLine(record));
这看起来不错,但是当我尝试考虑在程序中的其他地方修改底层数据时,当某种模型“附加”到该数据结构时,它会变得非常混乱。
例如,让我们看一下学习资料中的示例代码:
// addressbook/main.cpp
#include <QtGui>
#include "addressbookmodel.h"
int main( int argc, char* argv[] )
QApplication app( argc, argv );
QFile file("addressbook.csv");
if ( !file.open(QIODevice::ReadOnly|QIODevice::Text) )
return 1;
QString addresses = QString::fromUtf8(file.readAll());
AddressbookModel model(addresses);
QTableView tableView;
tableView.setModel(&model);
tableView.show();
return app.exec();
这里有一个静态变量addresses
,然后发送到model
。现在,用户将能够查看和修改该数据。但是,如果我想在程序的其他地方更多地使用这些数据怎么办?如果我向addresses
插入新条目怎么办?我意识到模型不会看到这些变化,并且在这个示例(以及更多示例)中,底层数据结构甚至不是作为指针发送的。
所以我的问题是:如何正确管理数据,什么时候我会有来自“幕后”的新数据——不仅仅是来自模型?我应该只在模型类中使用数据管理(实现所需的功能等)吗?我应该以某种方式仅将数据指针传递给模型吗?当我想到使用代理模型进行过滤时,一切都变得更加棘手,因为它们也可以工作并且以自己的方式“处理”数据。也许我错过了有关此架构的一些重要内容,但它确实让我停了下来。
【问题讨论】:
你应该从这里开始:doc.qt.io/qt-5/model-view-programming.html 好的,我会试着看看那个页面。虽然我觉得我见过很多,但这个看起来更广泛。 【参考方案1】:使用 Qts 数据模型可能会非常令人困惑。您将需要处理您自己的大部分“更新”。例如,如果您在 QAbstractItemModel::setData
的重载中更改模型数据,您将不得不自己发出 QAbstractItemModel::dataChanged
。插入、删除或移动条目也是如此。如果您有时间,您应该阅读 SaZ 发布的链接,但有关在哪个过载时发出什么内容的一些快速信息,您可以查看QAbstractItemModel Documentation。
关于“幕后”修改数据:
最佳做法是更改模型上的数据,即调用 QAbstractItemModel::setData
更改一些数据。但由于此函数旨在以“可显示格式”获取数据,因此最好创建自己的函数。在此函数内部,您需要“通知”模型您的更改。这样所有视图都会正确更新。
例如,如果您的“AddressRecord”具有name
属性:
void AddressbookModel::changeName(QModelIndex addressIndex, QString name)
//For this example I assume you are using a simple list model with only one column
//The addressIndex´s column is always 0 in this case, and the parent invalid
addressBook[addressIndex.row()].setName(name);
emit dataChanged(addressIndex, addressIndex);
如您所见,您将不得不以某种方式使用QModelIndex
-class,它表示模型中条目的位置。
我希望我至少能提供一点帮助,但 Qts 模型视图框架可能会非常棘手,尤其是当您必须添加、删除、移动或排序数据时。不过要想更深入的了解,恐怕还是要亲自试一试!
【讨论】:
谢谢,非常感谢您的回答,但是当使用代理模型时,所有这些与情况有何关系?它们就像模型的包装器一样工作,所以当我在源模型中编写所有数据处理逻辑时,我还能使用代理模型和这种数据处理方法吗?据我记得,我为视图设置代理模型,而不是源模型。 没错!如果您正确更改源模型中的数据,代理模型将收到这些更改的通知并执行其设计的任何操作。 (例如排序,过滤,...)并通知视图它对源模型中的更改生成的更改。当然,代理模型的实现也必须是正确的。以上是关于Qt 模型/视图:如何正确处理底层数据的主要内容,如果未能解决你的问题,请参考以下文章
如何彻底改变 QAbstractTableModel 的底层数据?