Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系。这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接口,使得更多的数据源可以被这些item view使用。这里对model/view的结构进行了描述,结构中的每个组件都进行了解释.。

一直觉得Qt里的Model-View概念极其神秘, 因为看过很多一知半解的source code, 却总是咋看咋不懂,急了满头大汗之余不禁感叹 — 老了,脑子不够用了!

这两天因为在写rssreader的关系,用到了MVC, 总算有点压力学习学习ModelView的奥秘,而且也小有收获。 谨以此文献给MVC未入门的学弟学妹, 共勉!

先来讲一些必备的背景知识。 在讲MVC时有三个重要且基本的概念贯穿整个学习过程:Index, Data和Role。 就从Index开始。

我们见过的View有单列的List结构, 有树状的层次结构,还有两维的表格结构, 归根结底,其实这些都是层次结构的变体。 比如下面的图:

从这张图可以清楚的理解上文的观点。 在这几种结构中,都有一个隐含的根节点及与根节点联系的层次结构。 任何一种结构中都存在这样一个定式, 通过一个父节点及一组横纵座标(row,column)即可唯一的确定一个子节点, 这个规律在后面会经常用到。Index可以简单的理解成节点的指针, 前面说过通过三个要素即可唯一的确定一个节点, 所以Model提供的获得节点index函数亦即接受row,column和parentindex三个参数, 我们在写model时首先需要实现这样一个函数;

第二个概念Data就更简单了,View要显示数据, 就要从Model中去获取需要显示的数据, 传什么参数呢? 不用动脑子也想的到咯,Index肯定算一个。 但仅仅Index并不够, 因为View要显示的可能不止一项数据,比如我的数据包含文本, 包含图标,包含链接甚至一些二进制数据, 我怎么知道View想要的是哪个呢? 这里就用到另外一个概念了 — Role, Role就用来表示View向Model索取哪个类型的数据。 View告诉Model:“我想要A节点下的N行M列数据的显示文本; 我想要A节点下的N行M列数据的图标…”, 这样Model就清楚的知道应该返回什么数据了。 data()函数在这里就充当了返回数据的责任,需要我们在实现Model的时候重点实现这个函数。

目前定义好的Role可以参考下面的图(图中只标出了一部分Role, 其他的参见文档DisplayRole相关章节):

作为Model必须决定为View提供多少数据,提供哪些类型的数据, 可以去满足View的请求,也可以忽略它, 有很大的自主权。 最简单的实现是不管什么Role都给它返回个字符串就好了。呵呵。 当然作为Model也不能太独断专行,因为毕竟要和View一起工作, 一定要与View的需求相配合才行。

好, 有了这些知识做基础, 写个Model出来其实是非常简单的, 稍微用点心就能应付了, 首先要选对参考文档, 如果是以写代码为目的, 推荐这一篇:

Creating New Models

要写code的话这篇最实用, 前面的N多篇都在讲一些概念性的内容, 大把大把的蚂蚁样的英文看了就头大, 还是直接看这篇比较有效。 简单来说分成几步来做:

第一、分析需求,确定基类

先要确定你的数据是列表结构还是层次结构, 需要显示什么样的数据, 需不需要支持增删或编辑功能等。 根据需求来确定从哪个Model的基类派生,如一个显示字符串列表的Model可以采用QAbstractListModel, 树状层次就只能从QAbstractItemModel开始了。

第二、分析需求,确定需要实现哪些函数

根据需求的不同,需要实现的函数也不尽相同。

最简单的只读的列表结构只需要实现两个基本的函数:rowCount(), data(), 也就是只需要知道一共有多少行,每行都显示什么样的数据即可, 十分明了吧? 多列的情况下要实现columnCount(), 需要显示header的要去实现headerData(), 这些规则都太容易理解了。

其次,如果是层次列表,则需要确定节点之间的层次关系,就需要实现index()和parent()两个函数, 一个是通过父指针和row,column座标确定一个子节点,一个是通过子节点知道它的父指针。

再次,如果需要修改数据, 先要通知View我的Model数据是可以被编辑的, 就是要实现flags()这个函数, 此函数返回数据的属性,如可编辑、可被选中等; 编辑之后需要一个函数将编辑完成的数据传递给Model, 所以还要实现一个setData方法。

再再次, 需要增删数据的Model还要告诉Model的底层:“我要增删数据了!”, “我要增删的数据是。。。”, 还有“我增删的操作已经做完了!”, 这些分别对应:调用beginInsertRows()和endInsertRows()。 根据笔者的经验,这部分不太好理解,而且容易出错。 文档里写的是加数据的时候调用insertRows(),不过没有提到说其实在QAbstractItemModel类里这个函数只是个空架子,根本就没有实现, 所以你如果按照文档去调用这个函数通知Model数据加进来了,只能得到一个return false, 不会有任何实际的作用, 很让人困惑。 正确的做法是在你增删数据的前后加上beginInsertRows和endInsertRows的调用,这样底层就能正确处理数据的变化, 并且将变化及时的反应到View中。

上面提到的函数在Creating New Models这篇文章中都有具体的例子代码可供参考,相信照着例子做一定难不倒大家。 btw,实现函数的时候要注意, 函数的声明必须和文档中所描述的一模一样才能被调到, 这也是初学者经常不注意的地方。

小结:QtWidget中自定义Model的内容介绍完了,希望本篇对你有帮助。Model与数据源通讯,并提供接口给结构中的别的组件使用。通讯的性质依赖于数据源的种类
model实现的方式。

转自:http://mobile.51cto.com/symbian-270166.htm

http://www.cnblogs.com/bingcaihuang/archive/2011/07/24/2115612.html

浅析在QtWidget中自定义Model(beginInsertRows()和endInsertRows()是空架子,类似于一种信号,用来通知底层)的更多相关文章

  1. 浅析在QtWidget中自定义Model

    Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接 ...

  2. QT内省机制、自定义Model、数据库

    本文将介绍自定义Model过程中数据库数据源的获取方法,我使用过以下三种方式获取数据库数据源: 创建 存储对应数据库所有字段的 结构体,将结构体置于容器中返回,然后根据索引值(QModelIndex) ...

  3. iOS自定义model排序

    在开发过程中,可能需要按照model的某种属性排序. 1.自定义model @interface Person : NSObject @property (nonatomic,copy) NSStri ...

  4. Qt自定义model

    前面我们说了Qt提供的几个预定义model.但是,面对变化万千的需求,那几个model是远远不能满足我们的需要的.另外,对于Qt这种框架来说,model的选择首先要能满足绝大多数功能的需要,这就是说, ...

  5. Sails 自定义 model 方法

    Sails 自定义 model 方法 在 Sails 中 model 提供了一些原生的静态方法,如 .create(), .update(), .destroy(), .find(), 等. 在实际业 ...

  6. Django中的Model(字段)

    Model Django中的model是用来操作数据库的,Model是一个ORM框架,我们只需要关心model的操作,而不需要关心到底是哪一种数据库. 一.基本知识: 数据库引擎: Django中自带 ...

  7. Django中的Model继承

    Django 中的 model 继承和 Python 中的类继承非常相似,只不过你要选择具体的实现方式:让父 model 拥有独立的数据库:还是让父 model 只包含基本的公共信息,而这些信息只能由 ...

  8. ASP.NET MVC4中的Model验证 移除指定验证信息

    MVC中通过Model在页面间传值使的程序开发变得更加的快捷,但是很多时候,我们在数据传递的时候为了确保数据的有效性,要对Model的相关属性做基本的数据验证. 不多说直接上个代码,Model的实体类 ...

  9. 浅析Thinkphp框架中运用phprpc扩展模式

    浅析Thinkphp框架中应用phprpc扩展模式 这次的项目舍弃了原来使用Axis2做web服务端的 方案,改用phprpc实现,其一是服务端的thinkphp已集成有该模式接口,其二是phprpc ...

随机推荐

  1. html+css+js实现狼吃羊小游戏

    html+css+js实现狼吃羊小游戏 一.总结 一句话总结:给动的元素下标记,这里表现为将要活动的标签动态增加class,这是一种很好的思想. 1.如何实现棋子走动的时候简单精确定位? 用重构坐标系 ...

  2. Android中获取当前位置的使用步骤

    在Android中得到当前位置的步骤 1.在AndroidManifest.xml中声明权限 android.permission.ACCESS_FINE_LOCATION(或者android.per ...

  3. 使用SecureCRT连接AWS的EC2

    如果使用CentOS等linux系统,直接使用ssh命令即可访问AWS上的Linux-EC2实例. $ ssh -i XXX.pem ec2-user@{IP/hostname} 在Windows系统 ...

  4. 《Windows核心编程》之“完成端口”(对所有IO都是如此,不仅仅是对socket)

    <Windows核心编程>第10章开头部分一再强调:“IO Completion Port”是“构建高性能.可升缩的应用程序”的最佳设施之一,它不仅适用于处理设备IO,也适用于其它越来越多 ...

  5. Spring boot传统部署

    使用spring boot很方便,一个jar包就可以启动了,因为它里面内嵌了tomcat等服务器. 但是spring boot也提供了部署到独立服务器的方法. 如果你看文档的话,从jar转换为war包 ...

  6. android仿新浪引导界面

    最近在研究如何做出仿微信,仿新浪等应用,第一次安装使用的使用展示应用程序的新特性和用法. 实现功能:左右手势滑屏 底部小圆点随当前显示页跳动 浮动按钮显示.当触屏事件发生显示,否则就渐渐消失 先转个文 ...

  7. 支付(异步通知notify_url 与 同步通知return_url的区别)

    同步通知和异步通知发送的数据没有本质的区别:同步通知有2个作用:第一是从支付宝的页面上返回自己的网站继续后续操作:第二是携带支付状态的get参数:让自己的网站用于验证: 同步通知后:还需要异步通知主要 ...

  8. linux 命令学习 —— 硬件外设管理(dmesg、lsusb)

    dmesg:print or control the kernel ring buffer dmesg命令设备故障的诊断是非常重要的.在dmesg命令的帮助下进行硬件的连接或断开连接操作时,我们可以看 ...

  9. CLR托管内存

    在物理内存中观察CLR托管内存及GC行为   虽然看了一些书,还网络上的一些博文,不过对CLR托管内存细节依然比较模糊.而且因为工作原因总会有很多质疑,想要亲眼看到内存里二进制数据的变化. 所以借助w ...

  10. Win7的diskpart硬盘分区

    Windows7 给硬盘分区有两个特点: 1.默认所有是主分区. 2.会有一个 100MB 大小的隐藏分区,为"系统预留". 假设喜欢折腾计算机,这两个特点会造成非常多麻烦.能不能 ...