本例和大家交流如何使用QAbstractItemModel定製自己想要的數據模型.
比如,突然想做一個類似QQ一樣的好友界面:
該怎麼弄?
先別慌,一步步來,今天就和大家交流如何簡單快捷的弄出一個類似的玩意兒。
(直接上代碼,相關說明已經註釋在代碼中。)
CFriendViewModel.h
#ifndef CFRIENDVIEWMODEL_H
#define CFRIENDVIEWMODEL_H
#include <QAbstractItemModel>
#include <QListView>
//* (示例所用)樹狀節點結構體
struct FriendViewItem
{
bool isGroup; //* 是否是分組(其實可以使用children.isEmpty來替代)
QString name; //* 名字
QList<FriendViewItem*> children; //* 子節點
};
typedef QList<FriendViewItem*> FriendViewItemList;
//*(示例所用)自定義樹狀model
class CFriendViewModel: public QAbstractItemModel
{
Q_OBJECT
public:
CFriendViewModel(QObject* parent = NULL);
~CFriendViewModel();
//* 用來提供View header部分的數據
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
//* 返回列數
virtual int columnCount(const QModelIndex & parent = QModelIndex()) const;
//* 獲取節點的數據
virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
//* 獲取某一個節點
virtual QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
//* 獲取某一個節點的parent
virtual QModelIndex parent(const QModelIndex & index) const;
//* 返回行數
virtual int rowCount(const QModelIndex & parent = QModelIndex()) const;
//* 設置原始數據
void setFriendViewItemList(const FriendViewItemList& li);
//* 返回原始數據
FriendViewItemList friendViewItemList();
private:
FriendViewItemList mItemList; //* 樹狀結構的原始數據(父節點list)
};
#endif // CFRIENDVIEWMODEL_H
CFriendViewModel.cpp
#include "CFriendViewModel.h"
CFriendViewModel::CFriendViewModel(QObject *parent)
:QAbstractItemModel(parent)
{
}
CFriendViewModel::~CFriendViewModel()
{
}
int CFriendViewModel::columnCount(const QModelIndex &parent) const
{
//* 本示例中只有一列數據
return 1;
}
QVariant CFriendViewModel::data(const QModelIndex &index, int role) const
{
//* 如果是無效節點則返回空數據
if(!index.isValid())
{
return QVariant();
}
//* 嘗試獲取原始數據
FriendViewItem* d = static_cast<FriendViewItem*>(index.internalPointer());
if(d == NULL)//* 沒有原始數據則返回空數據
{
return QVariant();
}
if(role == Qt::DisplayRole)//* 本例只返回了DisplayRole的數據
{
return d->name;
}
return QVariant();
}
QModelIndex CFriendViewModel::index(int row, int column, const QModelIndex &parent) const
{
//* 看父節點是否有效
if(!parent.isValid()) //* 無效的父節點(那肯定是分組)
{
QModelIndex groupIndex;
if(mItemList.count() > row) //* 使用有效的數據創建一個節點
groupIndex = createIndex(row, column, mItemList.at(row));
return groupIndex;
}
else //* 有效的父節點
{
//* 獲取父節點的數據
FriendViewItem* parentData = static_cast<FriendViewItem*>(parent.internalPointer());
if(parentData != NULL)
{
if(parentData->children.count() > row) //* 使用父節點下的對應row的子對象結構創建一個節點
{
QModelIndex childIndex = createIndex(row, column, parentData->children[row]);
return childIndex;
}
}
}
//* 沒有有效的數據項返回一個無效的節點
return QModelIndex();
}
QModelIndex CFriendViewModel::parent(const QModelIndex &index) const
{
//* 如果是無效的節點則返回無效節點
if(!index.isValid())
{
return QModelIndex();
}
FriendViewItem* indexData = static_cast<FriendViewItem*>(index.internalPointer());
for(int i = 0; i < mItemList.count(); i++)
{
if(mItemList[i] == indexData) //* 如果是父節點(分組)則返回無效父節點(分組沒有父節點)
{
return QModelIndex();
}
else
{
//* 試圖判斷該節點的父節點是不是mItemList[i]
for(int ii = 0; ii < mItemList[i]->children.count(); ii++)
{
if(indexData == mItemList[i]->children[ii]) //* mItemList[i] 成功匹配爲indexData的父節點
{
//* 使用mItemList[i]作爲數據創建一個父節點
QModelIndex parentIndex = createIndex(i,0,mItemList[i]);
return parentIndex;
}
}
}
}
//* 未匹配到有效的父節點數據,返回無效節點
return QModelIndex();
}
int CFriendViewModel::rowCount(const QModelIndex &parent) const
{
//* 父節點是否有效
if(!parent.isValid()) //* 無效的父節點(說明是分組)返回父節點個數
{
return mItemList.count();
}
//*父節點是有效的,獲取父節點原始數據
FriendViewItem* d = static_cast<FriendViewItem*>(parent.internalPointer());
if(d == NULL)
{
return 0;
}
//* 父節點的原始數據中的子節點個數即爲rowCount
return d->children.count();
}
void CFriendViewModel::setFriendViewItemList(const FriendViewItemList &li)
{
mItemList = li;
layoutChanged(); //* 通知View刷新數據
}
FriendViewItemList CFriendViewModel::friendViewItemList()
{
return mItemList;
}
QVariant CFriendViewModel::headerData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/ ) const
{
//* 只返回header的DisplayRole數據
if(role == Qt::DisplayRole)
return QString("this is friend view model.");
return __super::headerData(section, orientation, role);
}
主函數main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QTreeView>
#include "CFriendViewModel.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTreeView sampleFriendListView;
sampleFriendListView.show();
CFriendViewModel friendListModel;
//sample data
FriendViewItemList fli;
for(int i = 0; i <5 ;i++)
{
FriendViewItem* gi = new FriendViewItem;
gi->isGroup = true;
gi->name = QString("group %1").arg(i);
for(int ii = 0; ii < 10; ii++)
{
FriendViewItem* ci = new FriendViewItem;
ci->isGroup = false;
ci->name = QString("children %1").arg(ii);
gi->children << ci;
}
fli << gi;
}
friendListModel.setFriendViewItemList(fli);
sampleFriendListView.setModel(&friendListModel);
return a.exec();
}
運行一下。得到了一個拙劣的好友列表:
如果需要操作裏面的數據就使用
CFriendViewModel中的兩個方法:
//* 設置原始數據
void setFriendViewItemList(const FriendViewItemList& li);
//* 返回原始數據
FriendViewItemList friendViewItemList();
這樣我們就得到了一個屬於自己的好友列表,完成了偉大工程的第一步(最重要的是數據模型)。
接下來就是美化一下我們的TreeView了,不過那是另外一個故事了。