深入理解QT模型/视图编程(一)
关于MVC模式
说到这个,还是离不开MVC模式,model是数据的抽象,view是视图的抽象,controller是交互的抽象;之前有一篇文章简单介绍过一个MVC的例子;其中的关系大致可以用下面这段伪代码来了解:
model.setDataSource(xxx); //从xxx处拿到数据 view1.setModel(&model); //为视图指定模型,view注册成为model的观察者 view1.show(); //View类由用户自己定制 view2.setModel(&model); //为视图指定模型 view2.show(); //同一个模型具有不同的视图 //最后,控制器更改模型数据,实际是model提供对datasource的操作接口 // model的update_datasource方法最后会通知作为观察者的view,数据源发生改变,调用view之前注册的onNotify方法; controller.setdata(model);
MVC的关系可以用下图表示:
在这个图中,View是前端,负责向用户展示数据,同时,也可以提供交互逻辑,可以修改某些数据,最终想要达到修改的源数据的操作则需要借助controller操作model的接口,对DataSource进行更新,更新之后同时notify它的观察者,也就是最终View也需要Update自己的视图;
关于模型
这里注意,数据本身并不是存储在model中,数据源可以是数据库,文件,或者一个类,一个结构体等;只是说模型类型为数据的操作提供接口,方便我们的使用;QT中所有的模型都基于QAbstractItemModel类,然后为一些常用的视图提供了相应的模型,比如:QStringListModel 用于存储简单的QStringList列表,提供了如下接口用于快速操作QStringList数据源:
QStandardItemModel 用于管理复杂的树形结构数据,每一个数据项可以包含任意的数据;如果QT提供的这些标准模型无法满足需要,还可以子类化QAbstracItemModel 等基类创建自定义的模型;
关于视图
QListView将数据显示为一个列表,QTableView将模型显示在一个表格中,QTreeView将模型的数据项显示在具有层次的列表中;这些类都是基于QAbstractItemView抽象基类,也可以将其子类化来提供定制的视图;
关于委托
委托也被称为代理,可以通过委托定制数据的渲染和编辑方式;注意QT里面没有控制器的概念,而是采用了委托Delegate的概念来达到控制器的效果;委托和控制器的不同之处在于,委托除了可以Cover控制器的角色外,还可以对要渲染的item进行定制,也就是一旦我们为View指定了Delegate并重载了其paint方法,最终Model数据更改时,会触发signal,然后触发View的重绘,重绘的时候会调用Delegate的paint方法而不是默认的paint方法。这就是原先的item的默认paint委托给了DeleGate的paint,这就是委托的真正含义;大概就是下面这种关系;
其中Delegate和View是相同的颜色,代表他们是一体的;原先模型直接到View的paint,由委托代劳;原先模型到model的修改也由委托代劳;
这就是QT为什么叫它Delegate的原因,因为它把模型和View解耦了;Model和View各自和Delegate打交道,这可不就是委托的字面意思嘛