在上一篇文章中,已經對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);
}

運行程序:

好了,今天的分享就到這裡了,QStandardItemModel在模型中非常重要的,本篇文章只是帶你了解了其比較重要的幾個介面,關於它的更多用法,還需要你再深入理解。

最後也希望大家多多支持小豆君的創作,關注小豆君的公眾號「小豆君Qt分享」,最新文章都會在公眾號第一時間發布,也可加入C++Qt交流群,一起學習。


推薦閱讀:
查看原文 >>
相关文章