public:
StringListModel (const QStringList &strings, QObject *parent = 0)
: QAbstractListModel (parent), stringList(strings) {}
int rowCount (const QModelIndex &parent = QModelIndex()) const;
QVariant data (const QModelIndex &index, int role) const;
QVariant headerData (int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
private:
QStringList stringList;
};
除了构造函数,我们仅需要实现两个函数:rowCount ()返回model中的行数,data ()返回与特定model index对应的数据项。具有良好行为的model也会实现headerData (),它返回tree和table views需要的,在标题中显示的数据。
因为这是一个非层次结构的model,我们不必考虑父子关系。假如model具有层次结构,我们也应该实现index ()与parent ()函数。
Model的尺寸
我们认为model中的行数与string list中的string数目一致:
int StringListModel ::rowCount (const QModelIndex &parent) const
{
return stringList.count();
}
在缺省情况下,从QAbstractListModel 派生的model只具有一列,因此不需要实现columnCount()。
Model 标题与数据
QVariant StringListModel ::data (const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() >= stringList.size())
return QVariant();
if (role == Qt::DisplayRole)
return stringList.at(index.row());
else
return QVariant();
}
QVariant StringListModel ::headerData (int section, Qt::Orientation orientation,
int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal)
return QString("Column %1").arg(section);
else
return QString("Row %1").arg(section);
}
一个数据项可能有多个角色,根据角色的不同输出不同的数据。上例中,model中的数据项只有一个角色 ,
DisplayRole,然而我们也可以重用提供给DisplayRole的数据,作为别的角色使用,如我们可以作为ToolTipRole来用。
可编辑的model
上面我们演示了一个只读的model,它只用于向用户显示,对于许多程序来说,可编辑的list model可能更有用。我们只需要给只读的model提供另外两个函数flags()与setData()的实现。下列函数声明被添加到类定义中:
Qt::ItemFlags flags (const QModelIndex &index) const;
bool setData (const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
让model可编辑
delegate会在创建编辑器之前检查数据项是否是可编辑的。model必须得让delegate知道它的数据项是可
编辑的。这可以通过为每一个数据项返回一个正确的标记得到,在本例中,我们假设所有的数据项都是
可编辑可选择的:
Qt::ItemFlags StringListModel ::flags (const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsEnabled;
return QAbstractItemModel ::flags(index) | Qt::ItemIsEditable;
}
我们不必知道delegate执行怎样实际的编辑处理过程,我们只需提供给delegate一个方法,delegate会使用它对model中的数据进行设置。这个特殊的函数就是setData():
bool StringListModel ::setData (const QModelIndex &index,
const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole) {
stringList.replace(index.row(), value.toString());
emit dataChanged (index, index);
return true;
}
return false;
}
当数据被设置后,model必须得让views知道一些数据发生了变化,这可通过发射一个dataChanged() 信号实现。
因为只有一个数据项发生了变化,因此在信号中说明的变化范围只限于一个model index。
插入,删除行
在model中改变行数与列数是可能的。当然在本列中,只考虑行的情况,我们只需要重新实现插入、删除
的函数就可以了,下面应在类定义中声明:
bool insertRows (int position, int rows, const QModelIndex &index = QModelIndex());
bool removeRows (int position, int rows, const QModelIndex &index = QModelIndex());
既然model中的每行对应于列表中的一个string,因此,insertRows()函数在string list 中指定位置插入一个空string,
父index通常用于决定model中行列的位置,本例中只有一个单独的顶级项,困此只需要在list中插入空string。
bool StringListModel ::insertRows(int position, int rows, const QModelIndex &parent)
{
beginInsertRows (QModelIndex(), position, position+rows-1);
for (int row = 0; row < rows; ++row) {
stringList.insert(position, "");
}
endInsertRows ();
return true;
}
beginInsertRows()通知其他组件行数将会改变。endInsertRows()对操作进行确认与通知。
返回true表示成功。
删除操作与插入操作类似:
bool StringListModel ::removeRows(int position, int rows, const QModelIndex &parent)
{
beginRemoveRows (QModelIndex(), position, position+rows-1);
for (int row = 0; row < rows; ++row) {
stringList.removeAt(position);
}
endRemoveRows ();
return true;
}