请教QT中的standarditem modelModel怎么删除数据

Qt的模型/视图编程方法(model/view programming)
由于最近做的一个程序需要用一个视图显示所定义的数据,翻了下Qt的widget,有QTreeWidget,QTableWidget,QListWidget。但是这些widget内部包含了存储这些数据的container,也就是说用户产生的数据为了能够以列表或者树目录的形式显示出来,必须将其拷贝一份。这就造成了数据的冗余,对于数据不是很多的情况牺牲一点点空间也无妨,但是对于数据库等大型数据来讲,这便是无法原谅的了。翻了翻Qt 的帮助文档,Qt提供了一个框架完美得解决了这个问题:Model/View Programming。这种方法采用了将视图和数据分离的策略,视图只负责显示,不提供数据存储,而model中存储了自定义的数据,这样仅一份数据可以在多个视图中显示。这个思想类似于C++中容器和算法,一个存储数据,一个使用数据,它们之间的接口就是遍历器。本文算是学习笔记,网上的帮助文档加上自己实践花了1个多星期,在此总结一下。Qt4.7在线帮助文档:。模型/视图编程介绍&Qt 4引入了一系列基于模型/视图构架的类,用于管理数据及其呈现之间的关系。由这个构架带来的功能的分离能够使得开发者更加灵活地自定义数据的呈现方式。Qt也提供了一些标准的接口,能够使大部分数据可以用已有的视图来显示。在帮助文档中主要介绍了这些模块的大概,基本概念和基本函数的用法。给出了每一个部件的用法,也提供了一些例子。模型/视图构架模型-视图-控制器(MVC)是一个基本的设计模式。这种设计模式定义了3个部件。模型即应用实体,视图就是屏幕呈现,控制器定义了用户接口和对用户输入的反馈。在MVC之前,用户界面的设计将这些模块糅合到了一起。MVC从功能上将3个部件分开,从而提供了更多的灵活性和复用性。如果讲视图和控制器结合到一起,结果就是模型/视图构架。这种构架仍然将数据的存储和用户的呈现分开,能够使同一数据用不同的视图来显示,而不用改变内在的数据结构。为了能够灵活把握用户输入,Qt引入了代理(delegate)的概念。代理能够在视图中灵活定义用户将用哪种方式输入数值,是用LineEdit直接输入,还是用ComboBox选择,还是用SpinBox调节。&
模型与数据源想关联,并且提供了接口供构架中的其他模块访问数据,至于如何访问数据,决定于数据的类型和模块是如何实现与数据的相关的。视图从模型中获得数据的索引(index,专有类QModelIndex),这些索引是对数据的引用。在视图中,当数据元素需要编辑时,代理便负责提供编辑的接口,代理直接与模型通信,并使用模型提供的索引。
模型,视图和代理通过信号(signals)和槽(slots)相互通信:来自模块中的信号通知视图数据源中数据的改变。来自视图的信号提供了用户交互和数据显示方式的信息。当用户编辑数据时,代理发出信号,提示模型和视图编辑的状态等信息。先来看一下最基本的三个类,Model/View框架中其他的类都是派生自这三个基本类。QAbstractItemModel 这个类就是Model的抽象接口QAbstractItemView 这个是视图的抽象接口QAbstractItemDelegate View和model的&中间接口&,当你需要在视图中编辑item时,这个类就派上用场了。
模型提供了接口给视图和代理,但有一点要清楚,它并不提供数据的存储。数据并不存储在模型中,而存储在由一些数据结构中或者类所定义的另外的容器中,例如文件,数据库,或者别的应用程序部件中。QAbstractItemModel提供了足够的接口供表格,树形目录,列表等显示数据。但要用特定视图显示数据时,最好从QAbstractListModel、QAbstractTableModel中派生,它们提供了对一些常用函数更合适的默认实现。这些类通过子类化之后,能提供更加自定义的,更加特定的列表,表格视图。(一般子类化这三个抽象类)
Qt提供了一些已经完成的模型类来处理数据:
l QStringListModel:用列表来处理QString的数据。
l QStandardItemModel管理了复杂的树形结构。
l QFileSystemModel提供了本地文件系统中的文件和目录信息。
l QSqlQueryModel,QSqlTableModel,QSqlRelationalTableModel是用来存取数据库的。
已经定义好的视图有3个:QListView,QTableView,QTreeView。从名称可以看出来它们各自的功能,以后会一一介绍。这三个类都基于抽象类QAbstractItemView。
代理的抽象类是QAbstractItemDelegate,基于它的标准实现是QStyledItemDelegate,这个代理被用在以上3个标准视图中。然而还有一个代理QItemDelegate,它与QStyledItemDelegate是完全独立的两个代理类。因为QStyleItemDelegate使用当前风格绘制元素,所以当你用自定义代理或者使用Qt样式表的时候,最好是子类化这个。
使用模型和视图
下面将介绍如何使用模型/视图模式。
两个标准模型
Qt已经为我们实现了2种模型,QStandardItemModel和QFileSystemModel。QStandardItemModel是一个多用途的模型,可以用来表示多种不同类型的数据,可以显示在列表,表格,树视图中。这个模型存储了数据元素。
QFileSystemModel是一个维持了内容路径的模型,它自己不存储任何数据元素,仅仅表示了本地文件系统中的文件和路径。它拿来就能用,并能非常容易地设置好药显示的数据,用这个模型可以示范一下如何搭建一个可用使用的视图,同时也可以看看如何操作模型中数据的索引。
使用已经存在的模型搭建视图
QListView和QTreeView比较适合用来显示路径信息。下图中左边用了树状图,右边是列表视图。并且两个视图共享了用户的选择(即选择一个视图中的一个项目,另一个视图中的项目会同时被选中),选择项目牵扯到另外一些类,后面有详细探讨。
代码很简单:
这里index()的用法是专门针对QFileSystemModel的,给它一个路径,它返回一个QModelIndex值。这个类后面会讨论,专门用于对模型中每个项目的索引操作。
int main(int argc, char *argv[])
QApplication app(argc, argv);
QSplitter *splitter = new QS//QSplitter用户分割两个widget
QFileSystemModel *model = new QFileSystemM
model-&setRootPath(QDir::currentPath());
QTreeView *tree = new QTreeView(splitter);
tree-&setModel(model); //为视图设置模型
tree-&setRootIndex(model-&index(QDir::currentPath()));
QListView *list = new QListView(splitter);
list-&setModel(model);
list-&setRootIndex(model-&index(QDir::currentPath()));
splitter-&setWindowTitle("Two views onto the same file system model");
splitter-&show();
return app.exec();
int main(int argc, char *argv[]) { QApplication app(argc, argv); QSplitter *splitter = new QS//QSplitter用户分割两个widget QFileSystemModel *model = new QFileSystemM model-&setRootPath(QDir::currentPath()); QTreeView *tree = new QTreeView(splitter); tree-&setModel(model); //为视图设置模型 tree-&setRootIndex(model-&index(QDir::currentPath())); QListView *list = new QListView(splitter); list-&setModel(model); list-&setRootIndex(model-&index(QDir::currentPath())); splitter-&setWindowTitle("Two views onto the same file system model"); splitter-&show(); return app.exec(); }
到这里可能你还对模型视图框架中的基本概念还不是很清楚,这数据如何在model中存储呢?视图到底如何从Model中获取数据?让我来看看基本概念。
首先模型为视图和代理提供了一个标准接口用于存取数据,它就是QAbstractItemModel类。无论数据项是用什么数据结构存储的,QAbstractItemModel的子类(作为一个抽象类,你总要子类化一下才能用吧)总是用一种抽象的表结构来表示各个数据项。下面的图表示了数据的存储结构,可以发现数据都是以行、列的形式表示的,list和tree也可以有多个列。由此可以发现,其实ModelIndex对象里面应该有一个行号和一个列号用于表示其中一个数据项目。
当用setModel()设置好一个视图的model之后,模型和视图之间的联系通过信号和槽联系,当数据改变后,不管是在Model中改变的还是在视图中改变的,它们都能发出信号通知对方。
既然Model index与模型中数据表示息息相关,那就先讲这个模型索引。
模型索引(model index)
为什么要引入一个index来连接视图和模型呢?视图直接操作模型中的数据吗?Qt为了使它们分工明确,视图只管显示,模型只管存储,于是引入一个model index来存取数据提供给视图。于是视图类中只要定义一个接口函数,其参数为一个QModelIndex就行了,我不管里面的数据是什么样子的。代理类(delegate)也一样。
这样做的结果就是,只需要模型知道数据如何获得就可以了,另外一点就是模型操作的数据类型可以一般化定义,就是QVarient类(可以表示很多不同的Qt标准化类型)。Model index数据结构中也有一个其指代的模型的指针,这样使得有多个模型要显示时不至于混乱。
QAbstractItemModel *model = index.model();//获取index指代的模型
QAbstractItemModel *model = index.model();//获取index指代的模型
Model index获得的数据信息只是临时的,因为model可以实时地了解内部数据结构,但是index作为一个买了东西就走的顾客,可不知道你这商店里面到底有什么类型东西。于是Qt提供了一个回头客&&QPersistentModelIndex,据说可以更新model中的信息,这个以后再说。一般的index由类QModelIndex表示。
Index要知道数据项目...
人人移动客户端下载1957人阅读
& 在qt中,用到最多就是model/view的结构来表示数据层及表示层的关系。model用于给view提供数据。那如何来实现一个简单的树形model呢。
& 实现一个自己的model需要重载以下的方法:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole)
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
int rowCount(const QModelIndex &parent = QModelIndex())
int columnCount(const QModelIndex &parent = QModelIndex()) const&pre name=&code& class=&cpp&&QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole)
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value,
int role = Qt::EditRole);
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex())
QModelIndex parent(const QModelIndex &child)
virtual Qt::ItemFlags flags(const QModelIndex &index)
下面通过一个小例子来说明每个方法的作用。想实现下面一个树形结构。
既然实现一个model里面肯定得构造自己的数据结构。
class RowNode
RowNode() { m_pNode = NULL; }
~RowNode() {}
inline void setParent(RowNode *rowNode) { m_pNode = rowN }
inline RowNode *parent() { return m_pN }
RowNode *m_pN
model构造里
m_child1 = new RowNode();
m_child2 = new RowNode();
m_child2-&setParent(m_child1);
1)data方法:这个方法用于提供model所需要的各种数据。根据不同的index跟role返回不同的值。
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole)
&pre name=&code& class=&cpp&&if (Qt::DisplayRole == role)
RowNode *pRowNode = static_cast&RowNode *&(index.internalPointer());
if (m_child1 == pRowNode)
if (0 == index.column())
return &Test&;
else if (1 == index.column())
return &Icon&;
else if (2 == index.column())
return &comboBox&;
if (0 == index.column())
return &col0&;
else if (1 == index.column())
return &col1&;
return &col2&;
return QVariant();
2)setData:这个方法用于设置model的各种数据,根据不同的index跟role的值.原理跟data一样,这里就不直接写了,直接返回True.
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
3)rowCount:用于设置行数。需要注意的是返回是指parent下面有几个子,而不是指整个TableView有多少行。因为显示树形的话,返回的RowCount只是指那个父结点有几个子。
int rowCount(const QModelIndex &parent = QModelIndex())
&pre name=&code& class=&cpp&&if (! parent.isValid())
RowNode *pNode = static_cast&RowNode *&(parent.internalPointer());
if (pNode == m_child1)
4)columnCount:用于设置列数,这个是整个TableView的列数。
int columnCount(const QModelIndex &parent = QModelIndex())
5)headerData及setHeadData
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole)
&pre name=&code& class=&cpp&&
if (orientation == Qt::Vertical)
if (Qt::DisplayRole == role)
return &2&;
if (Qt::DisplayRole == role)
return &1&;
return QVariant();}
&bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole);
同data跟setData一样,但是是用于设置header的值,就是标题行及固定列的值。
6)index:用于设置返回的index的值。
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex())
&pre name=&code& class=&cpp&&
if (! parent.isValid())
return createIndex(row, column, m_child1);
return createIndex(row, column, m_child2);
7)parent:用于设置父index。
QModelIndex parent(const QModelIndex &child)
RowNode *pRowNode = static_cast&RowNode *&(child.internalPointer());
if (pRowNode == m_child2)
return createIndex(0, 0, m_child1);
return QModelIndex();
8)flags:用于返回model一些flags,如是否可以编辑的话,会加上Qt::itemIsEditable.
virtual Qt::ItemFlags flags(const QModelIndex &index)
&pre name=&code& class=&cpp&&
Qt::ItemFlags oFlags = QAbstractItemModel::flags(index);
return oFlags | Qt::ItemIsE
这样一个简单的model就实现了。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:16683次
排名:千里之外
原创:14篇
(1)(1)(1)(1)(1)(1)(1)(2)(1)(1)(1)(2)温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
追寻希望的星光,可能有时眼前出现的会是一片黑暗,但我知道,我一直有双隐形的翅膀,带我飞,给我希望,给我无穷的力量
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(341)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_095064',
blogTitle:'Qt Model/View 学习笔记 (四)',
blogAbstract:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}紧急!QT如何清空model后,仍然可以往model写入新的东西_百度知道

我要回帖

更多关于 item model 的文章

 

随机推荐