2024年6月14日发(作者:)

自定义model

Qt的model-view架构中的几个关键的概念。一个model中的每个数据元素都有

一个model索引。这个索引指明这个数据位于model的位 置,比如行、列等。

这就是前面我们曾经说到过的QModelIndex。每个数据元素还要有一组属性值,

称为角色(roles)。这个属性值并不是数据的 内容,而是它的属性,比如说,这

个数据是用来展示数据的,还是用于显示列头的?因此,这组属性值实际上是

Qt的一个enum定义的,比较常见的有 Qt::DisplayRole和Qt::EditRole,另

外还有Qt::ToolTipRole, Qt::StatusTipRole, 和Qt::WhatsThisRole等。并

且,还有一些属性是用来描述基本的展现属性的,比如Qt::FontRole,

Qt::TextAlignmentRole, Qt::TextColorRole, Qt::BackgroundColorRole等

list model

定位其中的一个数据只需要有一个行号通过QModelIndex::row()函数进行访

问;对于table model而言,这种定位需要有两个值:行号和列号,这两个值可

以通过QModelIndex::row()和 QModelIndex::column()这两个函数访问到。另

外,对于tree model而言,用于定位的可以是这个元素的父节点。

不仅仅是tree model,并且list model和table model的元素也都有自己的父

节点,只不过对于list model和table model,它们元素的父节点都是相同的,

并且指向一个非法的QModelIndex

所有的model,这个父节点都可以通过QModelIndex::parent()函数访问到。这

就是说,每个model的项都有自己的角色数据(属性),0个、1个或多个子节点。

既然每个元素都有自己的子元素,那么它们就可以通过递归的算法进行遍历,就

像数据结构中树的遍历一样,关于父节点的描述;

下面我们通过一个简单的例子来看看如何实现自定义model。

首先描述一下需求。这里我们要实现的是一个类似于货币汇率表的table

这是一个很简单的实现,直接用QTableWidget不就可以了吗?的确,如果直接

使用QTableWidget确实很方便。但是,试想一个包含了 100种货币的汇率表。

显然,这是一个二维表,并且,对于每一种货币,都需要给出相对于其他100

种货币的汇率(在这里,我们把自己对自己的汇率也包含在 内,只不过这个汇率

永远是1.0000)。那么,这张表要有100 x 100 = 10000个数据项。现在要求我

们减少存储空间。于是我们想,如果我们的数据不是显示的数据,而是这种货币

相对于美元的汇率,那么,其他货币的汇率都可以 根据这个汇率计算出来了。

比如说,我存储的是人民币相对美元的汇率,日元相对美元的汇率,那么人民币

相对日元的汇率只要作一下比就可以得到了。我没有必要 存储10000个数据项,

只要存储100个就够了。于是,我们要自己实现一个model(就是更优化的

model)。

CurrencyModel就是这样一个model。它

底层的数据

使用一个QMap

double>类型的数据,作为key的QString是货币名字,作为value的double

是这种货币对美元的汇率。然后我们来看代码:

class CurrencyModel : public QAbstractTableModel

{

public:

CurrencyModel(QObject *parent = 0);

void setCurrencyMap(const QMap &map);

int rowCount(const QModelIndex &parent) const;

int columnCount(const QModelIndex &parent) const;

QVariant data(const QModelIndex &index, int role) const;

QVariant headerData(int section, Qt::Orientation orientation,

int role) const;

private:

QString currencyAt(int offset) const;

QMap currencyMap;

};

CurrencyModel::CurrencyModel(QObject *parent)

: QAbstractTableModel(parent)

{

}

int CurrencyModel::rowCount(const QModelIndex & parent) const

{

return ();

}

int CurrencyModel::columnCount(const QModelIndex & parent) const

{

return ();

}

QVariant CurrencyModel::data(const QModelIndex &index, int role) const

{

if (!d())