24小时热门版块排行榜    

查看: 863  |  回复: 2
当前只显示满足指定条件的回帖,点击这里查看本话题的所有回帖

yalefield

金虫 (文坛精英)

老汉一枚

[交流] 【转帖】Qt的Model/View Framework解析 已有2人参与

http://blog.csdn.net/superjoel/archive/2009/12/31/5112120.aspx
作者:superjoel

看到一个老外在blog中写到:Model/View是他认为Qt中最不好的一部分了
真的是这样吗?
为了回馈开源社区,我写了这篇blog,写的是我认为比较有价值的东东。
题目起得是解析,但也没有特别细节的介绍,点到为止,有兴趣的Tx 可以继续讨论。我所看的资料有《C++ GUI Programming with Qt 4, Second Edition》、Qt官网和Qt源代码。

      在UI中,最常用的就是list/grid/tree了(在Qt中,grid被称为table)。尤其是做那些数据库相关的程序,可能每个界面都要用到 list或grid。在Qt中,它们被归为item view class。有两种实现,一种叫item based,这些类名以widget结尾,如QListWidget等。另一种叫model based,这些类以view结尾,如QListView等。

      item based widget使用起来很简单,与MFC中的CListCtrl/CTreeCtrl等差不多。
      这些类,既是数据容器(data container),又负责显示(presentation),还要处理与用户的交互(user action)。但,使用这些类的缺点,就是在处理大量数据显示时显得力不从心。
      我记得使用CListCtrl的report mode显示超过5万条记录时需要等待很长时间。因为它要把所有的数据都拷贝进来,再显示,比如这个list一次只能显示50条记录,但它把剩下的 49950条也拷贝进了内存,并为每条记录的显示都加上格式等额外的信息。
      我想这种实现对于专业的软件来说是无法接受的。那么,怎么提高它们的性能呢?
      有些人想出了virtual list/grid。它们显示之前并不需要把所有的数据都装进来,如有5万条记录,刚开始时它显示前50条,显示哪条时去取哪条。也就是说后49950条它不管,当用户移动滚动条或上下键改变显示内容时,它会根据一系列参数计算出目前需要显示哪几条。如1000-1050条,那么再去取这几条数据显示。
      由于实现起来有一定的难度,所以很多MFC实现的virtual list/grid显示出来都是“素颜”的(能快速显示出来已经不错了)。当然,coding无止境,这种取数据的方式我们称为delayed fetch,如果实现不好的化,当电脑速度慢且用户急速拖滚动条时也有可能出现白屏、拖尾、模糊等情况。所以,还可以做prefetch和caching来尽力避免这些情况。
      好了,这里铺垫的已经够多了,下面我们直奔主题。

      model based view就是我们今天要重点“解析”的。对应的UI类有QListView/QTreeView/QTableView。那么这些view与上面的 widget有什么区别呢?名字就是最大的区别。widget本来就是指小东东,而view可是很“大气”的视图哦。那么这些view大哥是怎么显示的呢?下面就说说我不愿多说、但又不得不说的一个设计模式:MVC (Model/View/Controller),model代表数据(data set),view代表显示(presentation),controller处理与用户交互(user action)

      MVC模式源自smalltalk,现在好像被用的很多了。它的作用其实是把上面介绍的类似CListCtrl这样的类解放出来,因为它们要干很多事情,太累了。还有就是对于有些程序员来说,实现一个功能复杂的类可能会力不从心。分成3个类每个类解决不同的问题可能更好实现。从软件工程的角度上讲,这种方式的decoupling可以降低系统风险。好了,关于MVC,大家想了解更多的话可以继续在网上搜索。

      模式是MVC,那么Qt是怎么实现的呢?我打开了Qt的官网介绍(http://qt.nokia.com/doc/4.6/model-view- programming.html)。我晕,看到了几十个类,而且很多都有继承关系。很容易让人迷失啊。不过不要紧,经过2天的学习,我对它们做了总结,见下图。Tx们可以从我这幅图开始,抓住该framework的主线,免得迷失在茫茫泪(类)海:-)

(待续)
回复此楼

» 猜你喜欢

» 本主题相关价值贴推荐,对您同样有帮助:

已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖

yfx2003

金虫 (著名写手)

发现高人啊

分析的的确非常地道

你的帖子我订阅了,呵呵
Signyournicknamehere
3楼2013-08-09 10:52:27
已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖
查看全部 3 个回答

yalefield

金虫 (文坛精英)

老汉一枚

一般来说,Model里面并没有真正存储数据(数据少的话也可以直接存储在Model 里),它的数据是从真正的“肉(raw)”里取得,如一个disk file,或database的query result set等等。
      那么,这个model究竟是干什么用的呢?说白了吧,它就是负责将“肉”数据获取并提供给view,然后将view所做的对“肉”数据的修改更新至真正的“肉”中。所以,读写文件、操作数据库、网络通讯等一系列与数据打交道的工作就在model中做了
      有的时候“肉”可能真的很肥,所以 model还有一项重要的工作就是把这些“肉”编号。这样就出现了Model Index这个非常重要的类。一般来说,它使用一个2维的编号(row/colum)来对“肉”编号。但对于tree这种有层次结构的数据来说,又加上一个parent index作为第3个编号。即:一个父亲下面的叶子也是从0,0开始编号,获取model index的时候用递归来实现。
      OK,现在model已经有了一堆编好号码的“肉”了,谁来买啊?“肉”便宜咯......
      View适时出现,注意,很多view可以同时来买同一块“肉”。(汗,不开玩笑了,这篇blog快水了)。当view需要显示某些数据时,它们通过 model index从model中获取数据(调用model的data函数,当model的data变化时,它也会自动发dataChanged signal给所有的view以便它们更新)。
      当然,在view中也可以调用model的setData函数来设定某个model index所对应的数据。这里要说明一下model中的数据,用QVarient来承载,可以是所有Qt支持的类型,比较贴心的是,数据可以分成多个角色 (role),例如Qt:isplayRole专用于显示,Qt::BackgroundRole用于显示背景色等等。所以在model中,你不光可以对“肉”进行编号,还可以对“肉”进行“深加工”,使它们更“好看”或是更“美味”。
      View组织这些数据并显示,但却没有做真正的显示工作,真正的工作留给了delegate。
      Delegate就是MVC中的C。view让它显示时它就在paint函数中显示。当然,你可以重载这个函数并实现你自己的显示。你还可以给一个 view设定row delegate和colum delegate专用于row和colum。当用户触发了view的edit trigger时(如双击鼠标或回车),view开始in place edit (beginEditing)。Delegate会在合适的地方创建一个合适的widget(如line edit或combo box等)处理用户的输入,用户输入完成以后delegate获取用户的输入并返回。这些输入可以通过调用model的setData函数保存到真正的 “肉”中。所以Delegate其实就是负责最终显示数据和处理用户交互的。
      既然由用户交互,最重要的肯定是用户的选择了。
      说一下selection model。View将用户选择的item index全部存入selection model中,显示的时候根据selection model的内容显示。另外,多个view可以共享同一个selection model,这样,当你选中其中的一个时,另一个view中的相应item也会被选中。
      最后总结一下。
      Smalltalk怎么实现的MVC我不清楚,但是Qt model/view framework对MVC的实现完全是基于C++的虚基类和虚函数特性。MVC各部分之间的联通除了应用signal/slot之外,就全是虚函数了。 Tx们如果有兴趣的话,可以看看model/view framework源代码中那些QAbstract开头的类,它们定义了统一的接口虚函数后,派生类只需要重新实现这些函数即可。这里再重复一下学习这部分时Tx们应该关注的2条主线。
      无论什么view,作用都是把数据显示出来,那么第一条主线是数据怎样从数据源显示到view中。
      显示的数据可能被修改,所以第二条主线就是修改后的数据怎样再更新至数据源中。如果你能把这2幅sequence map画出来,相信你就已经完全明白了。
      我不知道Qt在这里的设计是不是做了太多的decoupling。反正灵活性是足够了(model/view/delegate都可以继承),但无法让程序员快速掌握。虽然Qt已经弱化了delegate并而且为view提供默认的delegate。但在做具体项目时,程序员大部分时候还是要根据具体情况重写派生类数的。这对于那些想快速做界面并显示的程序员来说,可能会难以接受
      总之,这个轮子做的是足够精细了,但一般在使用之前你还要自己拧点螺丝,上点油。
2楼2011-01-31 14:22:20
已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖
普通表情 高级回复 (可上传附件)
最具人气热帖推荐 [查看全部] 作者 回/看 最后发表
[考研] 332求调剂 +3 ydfyh 2026-03-17 3/150 2026-03-19 10:14 by 功夫疯狂
[考研] 0817 化学工程 299分求调剂 有科研经历 有二区文章 +9 rare12345 2026-03-18 9/450 2026-03-19 09:46 by 30660438
[考研] 304求调剂 +6 司空. 2026-03-18 6/300 2026-03-18 23:03 by 星空星月
[考研] 331求调剂(0703有机化学 +7 ZY-05 2026-03-13 8/400 2026-03-18 14:13 by 007_lilei
[考研] 268求调剂 +7 好运连绵不绝 2026-03-12 8/400 2026-03-17 20:28 by xilongliang
[硕博家园] 湖北工业大学 生命科学与健康学院-课题组招收2026级食品/生物方向硕士 +3 1喜春8 2026-03-17 5/250 2026-03-17 17:18 by ber川cool子
[考研] 考研化学学硕调剂,一志愿985 +4 张vvvv 2026-03-15 6/300 2026-03-17 17:15 by ruiyingmiao
[考研] 有没有道铁/土木的想调剂南林,给自己招师弟中~ +3 TqlXswl 2026-03-16 7/350 2026-03-17 15:23 by TqlXswl
[考研] 药学383 求调剂 +3 药学chy 2026-03-15 4/200 2026-03-16 20:51 by 元子^0^
[考博] 东华理工大学化材专业26届硕士博士申请 +6 zlingli 2026-03-13 6/300 2026-03-15 20:00 by ryzcf
[考研] 085601材料工程315分求调剂 +3 yang_0104 2026-03-15 3/150 2026-03-15 10:58 by peike
[考研] 297一志愿上交085600求调剂 +5 指尖八千里 2026-03-14 5/250 2026-03-14 17:26 by a不易
[考研] 一志愿哈工大材料324分求调剂 +5 闫旭东 2026-03-14 5/250 2026-03-14 14:53 by 木瓜膏
[考研] 考研调剂 +4 芬达46 2026-03-12 4/200 2026-03-13 16:04 by ruiyingmiao
[考研] 307求调剂 +5 超级伊昂大王 2026-03-12 5/250 2026-03-13 15:56 by 棒棒球手
[考研] 工科材料085601 279求调剂 +8 困于星晨 2026-03-12 10/500 2026-03-13 15:42 by ms629
[考研] 土木第一志愿276求调剂,科研和技能十分丰富,求新兴方向的导师收留 +3 土木小天才 2026-03-12 3/150 2026-03-13 15:01 by JourneyLucky
[考研] 289求调剂 +3 李政莹 2026-03-12 3/150 2026-03-13 11:02 by 求调剂zz
[考研] 0817化学工程与技术考研312分调剂 +3 T123 tt 2026-03-12 3/150 2026-03-13 10:49 by houyaoxu
[考研] 321求调剂(食品/专硕) +3 xc321 2026-03-12 6/300 2026-03-13 08:45 by xc321
信息提示
请填处理意见