1 模型/视图架构
1.1 模型
所有的模型都是基于QAbstractItemModel类,这个类定义了一个接口,可以供视图和委托来访问数据。
Qt提供的现成模型:
QStringListModel:用来存储一个简单的QString项目列表
QStandardItemModel:管理复杂的树型结构数据项,每一个数据项可以包含任意数据
QFileSystemModel:提供了本地文件系统中文件和目录的信息
QSqlQueryModel,QSqlTableModel和QSqlRelationalTableModel来访问数据库
1.2 视图
QListView:将模型的数据项显示为一个列表
QTableView:将模型的数据显示成表格
QTreeView:将模型的数据显示在树中
1.3 委托
定制数据的渲染和编辑方式
QStyledItemDelegate:使用当前样式来绘制它的项目,要实现自定义的委托或者要和Qt样式表一起应用时,建议使用它
QItemDelegate:
#include <QApplication>
#include <QFileSystemModel>
#include <QTreeView>
#include <QListView>
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
//创建文件系统模型
QFileSystemModel model;
//指定根目录
model.setRootPath(QDir::currentPath());
//创建树形视图
QTreeView tree;
//为视图指定模型
tree.setModel(&model);
//指定根索引
tree.setRootIndex(model.index(QDir::currentPath()));
//创建列表视图
QListView list;
list.setModel(&model);
list.setRootIndex(model.index(QDir::currentPath()));
tree.show();
list.show();
return app.exec();
}2 模型类
2.1 模型索引(为了确保数据的表示与数据的获取相分离)QModelIndex类提供
QModelIndex是临时引用,随着模型的结构改变而改变,
QPersistentModelIndex:用于长时间的引用
获取数据项的模型索引,必须指定模型的3个属性:行号,列号和父项的模型索引
2.2 行和列
一个模型可以把它看成一个简单的表格来访问,每个数据项可以使用行号和列号来定位
2.3 父项
顶层数据项的父项是QModelIndex()
2.4 项角色
标准的角色由Qt::ItemDataRole来定义
#include <QApplication>
#include <QStandardItemModel>
#include <QTreeView>
#include <QDebug>
#include <QStandardItem>
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
//创建标准数据项模型
QStandardItemModel model;
//获取模型的根项,根项不可见
QStandardItem * parentItem = model.invisibleRootItem();
//创建标准项item0,并设置显示文本,图标和工具提示
QStandardItem *item0 = new QStandardItem;
item0->setText("A");
QPixmap pixmap0(50,50);
pixmap0.fill("red");
item0->setIcon(pixmap0);
item0->setToolTip("indexA");
//就标准项item0作为根的子项
parentItem->appendRow(item0);
//就创建的标准项item0,作为新的父项
parentItem = item0;
//为item0创建子项
QStandardItem *item1 = new QStandardItem;
item1->setText("B");
QPixmap pixmap1(50,50);
pixmap1.fill(("blue"));
item1->setIcon(pixmap1);
item1->setToolTip("indexB");
parentItem->appendRow(item1);
//创建新的标准项,设置文本,图标,工具提示
QStandardItem *item2 = new QStandardItem;
QPixmap pixmap2(50,50);
pixmap2.fill(("green"));
item2->setData("C",Qt::EditRole);
item2->setData("indexC",Qt::ToolTipRole);
item2->setData(QIcon(pixmap2),Qt::DecorationRole);
parentItem->appendRow(item2);
QTreeView view;
view.setModel(&model);
view.show();
QModelIndex indexA = model.index(0,0,QModelIndex());
qDebug() << "indexA row count:" << model.rowCount(indexA);
QModelIndex indexB = model.index(0,0,indexA);
qDebug() << "indexB text:" << model.data(indexB,Qt::EditRole).toString();
qDebug() << "indexB toolTip:"
<< model.data(indexB,Qt::ToolTipRole);
return app.exec();
}
3 创建新的模型
3.1 创建只读模型
3.1.1 添加新类:StringListModel,基类:QAbstractListModel,继承自QObject
3.1.2 修改stringlistmode.h头文件
因为QAbstractItemMode本身不存储任何数据,只提供了一个访问数据的接口,所以将StringList作为数据源,
public:
explicit StringListModel(const QStringList &strings,QObject *parent = 0);
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; //作为模块的数据源
添加函数的实现
int StringListModel::rowCount(const QModelIndex &parent) const
{
return stringList.count(); //返回item的个数
}
//获取索引项对应的数据
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);
}main.cpp
int main(int argc,char* argv[]) {
QApplication app(argc,argv);
//为模型构造数据
QStringList list;
list << "a" << "b" << "c" ;
StringListModel model(list);
QListView listView;
listView.setModel(&model);
listView.show();
QTableView tableView;
tableView.setModel(&model);
tableView.show();
return app.exec();
}
3.2 添加编辑功能
添加flags()与setData,flags函数不知道是干什么的?有懂得可以留言下
Qt::ItemFlags flags(const QModelIndex &index) const; //
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); //变更数据实现函数
Qt::ItemFlags StringListModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) return Qt::ItemIsEnabled;
return QAbstractItemModel::flags(index)|Qt::ItemIsEditable;
}
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); //发出数据变更的信号,左上的index,右下的index
return true;
}
return false;
}修改data()
if (role == Qt::DisplayRole || role == Qt::EditRole) return stringList.at(index.row());
3.3 插入和删除行
需要添加两个函数insertRows和removeRows
//row位置,count行数,parent父项索引
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());实现两个函数
bool StringListModel::insertRows(int row, int count, const QModelIndex &parent)
{
beginInsertRows(QModelIndex(),row,row+count-1);
for (int loop = 0; loop < count; loop++ ) {
stringList.insert(row,"");
}
endInsertRows();
return true;
}
bool StringListModel::removeRows(int row, int count, const QModelIndex &parent)
{
beginRemoveRows(QModelIndex(), row, row+count-1);
for (int loop = 0; loop < count; loop++) {
stringList.removeAt(row);
}
endRemoveRows();
return true;
}