zoukankan      html  css  js  c++  java
  • 【转】Qt Mode/View

    1、view与Widget

        在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来尽力避免这些情况。好了,这里铺垫的已经够多了,下面我们直奔主题。

    2、Model/View

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

    <a> Model   

        一般来说,Model里面并没有真正存储数据(数据少的话也可以直接存储在Model里),它的数据是从真正的“肉(raw)”里取得,如一个disk file,或database的query result set等等。那么这个model究竟是干什么用的呢?说白了吧,它就是负责将“肉”数据获取并提供给view,然后将view所做的对“肉”数据的修改更新至真正的“肉”中。所以,读写文件、操作数据库、网络通讯等一系列与数据打交道的工作就在model中做了。有的时候“肉”可能真的很肥,所以 model还有一项重要的工作就是把这些“肉”编号。这样就出现了QModelIndex这个非常重要的类。一般来说,它使用一个2维的编号(row/colum)来对“肉”编号。但对于tree这种有层次结构的数据来说,又加上一个parent index作为第3个编号。即一个父亲下面的叶子也是从0,0开始编号,获取model index的时候用递归来实现。OK,现在model已经有了一堆编好号码的“肉”了,谁来买啊?“肉”便宜了。。。。。。

        Model数据索引(Index)

        model中的项可以作为各种角色来使用,这允许为不同的环境提供不同的数据。举例来说,Qt::DisplayRole被用于访问一个字符串,它作为文本会在view中显示。典型地,每个数据项都可以为许多不同的角色提供数据,标准的角色在Qt::ItemDataRole中定义。我们可以通过指定 model index与角色来获取我们需要的数

    QVariant value = model->data(index, role);

    Model 项角色

        角色指出了从model中引用哪种类型的数据。views可以用不同的形式显示角色,因此为每个角色提供正确的信息是非常重要的。通过为每个角色提供适当数据,model也为views和delegates提供了暗示,如何正确地把这些数据项显给用户。不同的views可以自由地解析或忽略这些数据信息,对于特殊的场合,也可以定义一些附加的角色。

     

    <b> View   

       View适时出现,注意,很多view可以同时来买同一块“肉”。(汗,不开玩笑了,这篇 blog快水了)。当view需要显示某些数据时,它们通过model index从model中获取数据(调用model的data函数,当model的data变化时,它也会自动发dataChanged signal给所有的view以便它们更新)。当然,在view中也可以调用model的setData函数来设定某个model index所对应的数据。这里要说明一下model中的数据,用QVarient来承载,可以是所有Qt支持的类型,比较贴心的是,数据可以分成多个角色 (role),例如Qt::DisplayRole专用于显示,Qt::BackgroundRole用于显示背景色等等。所以在model中,你不光可以对“肉”进行编号,还可以对“肉”进行“深加工”,使它们更“好看”或是更“美味”。View组织这些数据并显示,但却没有做真正的显示工作,真正的工作留给了delegate。

    <c> Delegate 

        Delegate就是MVC中的Controller。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也会被选中。

    3、小结

        最后总结一下,Smalltalk怎么实现的MVC我不清楚,但是Qt model/view framework对MVC的实现完全是基于C++的虚基类和虚函数特性。MVC各部分之间的联通除了应用signal/slot之外,就全是虚函数了。 Tx们如果有兴趣的话,可以看看model/view framework源代码中那些QAbstract开头的类,它们定义了统一的接口虚函数后,派生类只需要重新实现这些函数即可。这里再重复一下学习这部分时Tx们应该关注的2条主线:
        (1)、无论什么view,作用都是把数据显示出来,那么第一条主线是数据怎样从数据源显示到view中。
        (2)、显示的数据可能被修改,所以第二条主线就是修改后的数据怎样再更新至数据源中。如果你能把这2幅sequence map画出来,相信你就已经完全明白了。
        我不知道Qt在这里的设计是不是做了太多的decoupling。反正灵活性是足够了(model/view/delegate都可以继承),但无法让程序员快速掌握。虽然Qt已经弱化了delegate并而且为view提供默认的delegate。但在做具体项目时,程序员大部分时候还是要根据具体情况重写派生类数的。这对于那些想快速做界面并显示的程序员来说,可能会难以接受。总之,这个轮子做的够精细,但一般在使用之前你还要自己拧点螺丝,上点油。

    本文转自:http://blog.csdn.net/leo115/article/details/7532682

    本文参考:http://blog.csdn.net/debugconsole/article/details/38307313

  • 相关阅读:
    yaml文件执行后常见错误解决
    动态存储管理实战:GlusterFS
    Kubernetes角色访问控制RBAC和权限规则(Role+ClusterRole)
    Kubernetes 存储系统 Storage 介绍:PV,PVC,SC
    在容器中管理数据的两种方式
    k8s 如何关联pvc到特定的pv
    Mysqldump 的 的 6 大使用场景的导出命令
    Docker 容器日志管理
    k8s中节点级别的日志
    k8s中pod的容器日志查看命令
  • 原文地址:https://www.cnblogs.com/PrimeLife/p/4484827.html
Copyright © 2011-2022 走看看