在上一篇文章中,已经对Qt模型视图框架有了一个大致的了解,这篇文章我们主要来看一下模型基类QStandardItemModel的用法。

一般地,使用QStandardItemModel作为数据模型已经足够满足我们的需求了。这是因为它实现了QAbstractItemModel接口,这意味着该模型可以为任何支持该接口的视图中提供数据(例如QListView、QTableView和QTreeView,以及您自己的自定义视图)。

对于性能和灵活性,您可能想要子类化QAbstractItemModel来为不同类型的数据存储库提供支持。例如,QDirModel为底层文件系统提供了一个模型接口。

QStandardItemModel使用QStandardItem作为数据支撑。

1 QStandardItemModel常用方法介绍:

对于数据的操作,无非就是增删改查,我们就以这四个方面来对QStandardItemModel的方法进行介绍,因为QStandardItem是单个数据项的载体,所以这里我们只要能获取QStandardItem就可以很容易的获取数据。以下的数据操作,均指操作QStandardItem。

1.1 查询数据

1.1.1 item(int row, int column = 0) const

该接口可根据行号和列号返回QStandardItem指针。如果是一个树视图,通过这个接口,只能获取顶层item。想要获取下一分支的item可以使用QStandardItem的child接口。

1.1.2 invisibleRootItem() const

对于每个顶层item,其实它都是一个不可见item的子item,如果想要便利所有顶层item,可以使用如下方法。

QStandardItemModel* model = new QStandardItemModel;
QStandardItem* rootItem = model->invisibleRootItem();
for (int i = 0; i < rootItem->rowCount(); ++i)
    for (int j = 0; j < rootItem->columnCount(); ++j)
        QStandardItem* item = rootItem->child(i, j);
        //do somting ... 
}


当然,你也可以使用QStandardItemModel::rowCount和QStandardItemModel::columnCount来遍历顶层item,但如果你是递归遍历一棵树时,应该使用invisibleRootItem()的方法来遍历,因为这会为你遍历树提供一个统一的方法。否则你必须编写两个方法。

1.1.3 itemFromIndex(const QModelIndex &index) const

通过QModelIndex来获取item,QModelIndex 是一个用于定位item的类,关于这个类我会在后面的文章专门介绍。而且这个接口也是经常使用的,所以你最好记住它。

1.1.4 rowCount和columnCount可分别获取行数和列数

1.1.5 data(const QModelIndex &index, int role = Qt::DisplayRole) const

这个接口非常重要,它可以根据QModelIndex获取item中保存的数据,这对于快速检索出item所代表的数据是非常有用的。

因为一个item可以代表很多不同类型的数据,那么我们可以根据role这个参数来获取该item对应的某类数据,这里的默认参数是DisplayRole,即表示获取item其本身显示的数据。当然,如果你传递一个Qt::ToolTipRole,那么它将返回一个提示信息对应的数据。如果你想获取用户自定义类型,那么可以传递一个int类型,但这个类型要不小于Qt::UserRole。

data接口返回一个QVariant类型,这表明在item中可以存储QString,int,bool,Point,QRect,QVector3D等,也支持用户自定义类型,但你必须要先使用Q_DECLARE_METATYPE宏来向元对象系统进行注册声明。

与data接口相对应的是setData,用来设置数据。

1.1.6 findItems(const QString &text, Qt::MatchFlags flags = Qt::MatchExactly, int column = 0) const

返回在给定列中使用给定标志匹配给定文本的item列表。

1.2 添加数据

1.2.1 appendRow(QStandardItem *item)

添加数据到模型的最后一行,与其相同的有insertRow(),insertColumn()。

该接口的另一个重载形式是appendRow(const QList&items) 其参数是一个QList列表,如果所使用的视图是一个table或者是一个tree,则该列表表示一行数据中的多列数据。

1.2.2 setRowCount(int) ,setColumnCount(int)

设置行数, 设置列数

1.3 修改数据

1.3.1 setItem(int row, int column, QStandardItem *item)

将item放置到表中

1.3.2 setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)

设置index对应的item数据

1.4 删除数据

1.4.1 clear()

从模型中删除所有项。

1.4.2 removeRow()或removeColumn()

删除行,删除列。 在删除多行数据时,一定要注意索引问题。 请看一个删除文本为“apple”的程序

for (int i = 0; i < model->rowCount(); ++i)
    QStandardItem* item = model->item(i);
    if (item->text() == "apple")
        model->removeRow(i);
}


如果,这个列表中包含有多个有apple的item,则执行这部分代码时,程序不能正确的删除所有apple项。 不知道你有没有看出来,当从model中第一次删除了文本为"apple"的item后,model的行数就少了一行,且其后一项的索引自动的减一,当下一次再删除apple项时,很可能就跳过了apple项。

为了解决这个问题,可以使用倒叙的方法,即从列表的最后一项起,向前删除item,这是一个很不错的想法,而且也很实用。

你也可以使用findItme找出所有符合条件的item,然后删除它们。

2 示例程序

standarditemmodelwidget.h

#ifndef STANDARDITEMMODELWIDGET_H
#define STANDARDITEMMODELWIDGET_H
#include <QWidget>
class StandardItemModelWidget : public QWidget
    Q_OBJECT
public:
    StandardItemModelWidget(QWidget *parent = 0);
#endif // STANDARDITEMMODELWIDGET_H


standarditemmodelwidget.cpp

#include "standarditemmodelwidget.h"
#include <QDebug>
#include <QPushButton>
#include <QStandardItemModel>
#include <QVBoxLayout>
#include <QListView>
#include <QWidget>
StandardItemModelWidget::StandardItemModelWidget(QWidget *parent) :
    QWidget(parent)
    //创建界面
    QVBoxLayout* layout = new QVBoxLayout(this);
    QStandardItemModel* model = new QStandardItemModel;
    QListView* view = new QListView;
    view->setModel(model);
    layout->addWidget(view);
    //向model中添加数据
    QStringList textList;
    textList << "apple 1" << "apple 2" << "orange" << "banana" << "apple 3" << "red apple";
    for(auto& text: textList)
        QStandardItem *item = new QStandardItem(text);
        model->appendRow(item);
        item->setEditable(false);//设置每个item为不可编辑
    //检索所有的包含apple的数据项
    const int customRole = Qt::UserRole;
    QList<QStandardItem*> appleItems = model->findItems("apple", Qt::MatchContains);
    foreach (QStandardItem* appleItem, appleItems)
        //为apple项设置一个随机生成的颜色图标
        QPixmap pixmap(25,25);
        QColor clr(qrand()%255, qrand()%255, qrand()%255);
        pixmap.fill(clr);
        appleItem->setIcon(QIcon(pixmap));
        appleItem->setToolTip(clr.name());
        appleItem->setData(clr.name(), customRole);
    //当点击item时,在控制台输出其保存的颜色值
    connect(view, &QListView::clicked, [=](const QModelIndex &index){
        QStandardItem* item = model->itemFromIndex(index);
        qDebug() << item->data(customRole).toString();
    //点击按钮删除所有apple项
    QPushButton* btn = new QPushButton("删除以apple开头的项");
    layout->addWidget(btn);
    connect(btn, &QPushButton::clicked, [=](){
        QList<QStandardItem*> appleItems = model->findItems("apple", Qt::MatchContains);
        for (int i = appleItems.size()-1; i >= 0; --i)
            model->removeRow(appleItems.at(i)->row());
    resize(200, 400);
}


运行程序:

image


好了,今天的分享就到这里了,QStandardItemModel在模型中非常重要的,本篇文章只是带你了解了其比较重要的几个接口,关于它的更多用法,还需要你再深入理解。


最后也希望大家多多支持小豆君的创作,关注小豆君的公众号“ 小豆君Qt分享 ”,最新文章都会在公众号第一时间发布,也可加入C++\Qt交流群,一起学习。

Qt开发技术:图形视图框架(二)场景QGraphicsScene、QGraphicsItem与QGraphicsView详解
Qt开发技术:图形视图框架(二)场景QGraphicsScene、QGraphicsItem与QGraphicsView详解
VTK 基础(一) — 常用控件介绍及实现圆锥体绘制
最近在做医学图像的相关处理,其中用到了可视化程序包 VTK,在学习过程中,准备写一系列相关教程,一方面用于巩固自己所学,主要自己太笨图片,另一方面加强一下知识理解。 利用 VTK 进行绘制物体时,常用到的组件有下面几种,为了加深理解,VTK 把一个物体的渲染过程比喻成了一场演出(真的很形象图片):