目录
0. 前言
一直想学一下Qt下的Model/View
编程方法,但是搜了一圈CSDN
上可能还没有一套比较完整的博客。就想着好好学,啃一啃官方文档,结合自己的理解,开这个Qt Model/View专栏,将自己学习理解的过程记录下来。
本专栏基本上参考官方教程Qt Model/View Programming,也可以在安装的Qt Assistant
中搜索Model/View
找到官方教程,Qt5以上的版本应该教程区别不会太大。
本文主要探究Qt的Model/View
框架到底是什么,它能在什么情况下给我们带来何种便利。
1. 初识Model/View
1.1 故弄玄虚
在Qt中最容易看到的关于该框架内容的位置应该在下图,在Qt Creator
中编辑界面时的控件,有Model-Based
和Item-Based
两种。
我自己的体会是:一般就用下面的Widget
了,它的接口理解起来比较简单,也不像上面的View
那样,不但运行起来啥也没有,好不容易找到一个setModel()
接口,但使用之后一言不合就容易崩溃。
这给人一种故弄玄虚的感觉:明明放在很显眼的位置,但使用起来却门槛过高。不是说Qt很容易嘛?
1.2 优越感
另外,在使用Item-Based
控件时,官方文档中无时无刻不在提醒着Model-Based
控件的高级性:
比如官方文档在QListWidget
的介绍中写道:如果想要一个更灵活的列表控件,请使用一个带有标准模型的QListView
。
又如在QTableWidget
的介绍中:如果想使用自己的数据模型,你应该用QTableView
而不是本类。
好吧,那么充满高级感的功能,不得学习一下(去装X )?打开官方文档的Model/View Programming
教程看一眼,这个篇幅的全英文文档,当场劝退了,直呼“我不配”。
在认怂了相当多次,发现了一些可能确实需要使用Model/View
框架的场合之后,终于下定决心啃一啃了,来吧。
2. 什么是Model/View
2.1 起源
Qt
的Model/View
来源于SmallTalk
语言的MVC框架(Model-View-Controller
,模型-视图-控制器),模型指底层数据的模型,视图指上层表现形式,控制器负责将数据与视图连结,实现数据与视图分开的效果。
数据和视图的分开本质上是工作内容解耦,提升工作效率和专注度,比如前端和后端的分开也是解耦的结果。
MVC
提出已经过去几十年了,出现了很多变种,Qt的Model/View
也可以看做一种变种,它将视图与控制器结合了,所以只剩下Model
和View
了。
2.2 初探
官方教程的图片对于这二者的关系描述得再清楚不过了:
不过看到这个图首先就会有一个疑问:Model不是数据模型吗?怎么还有一个Data?
这或许是一个理解MVC的难点,很多人容易将二者混淆。
Data
是代码中具体的数据结构,Model
是对这些数据的解析方法,View
根据Model
的解析方法来展示视图内容。
此处举一个简单例子帮助理解:
从这里可以看出来,底层数据可以很散漫,甚至不一定是一维数组,一堆散装变量也没问题,经过
Model
解析映射以后可以基本看不出原有的样子了,然后View
的表现形式可以很丰富,甚至与数据可能看起来毫不相干。
另外,还应该有一个问题:不是说好的Model/View,这个多出来的Delegate是什么鬼?
这个👻建议现阶段暂时不要深究它,理由如下:
- 在以实现基本功能为目标的时候,可以不使用它;
Delegate
的上手难度大于Model
和View
,可能会存在一些和QPainter、QStyle
之类的梦幻联动,前期去接触它容易劝退;
这里大概讲一下它能干什么:
- 在不主动使用
Delegate
时,Qt会提供一个默认的Delegate
来完成视图的渲染(rendering
); 它的做法基本是将模型中的数据解析为字符串(QString
),然后设置到视图对应位置; - 它提供了在
View
上编辑数据的功能;
3. 为什么使用Model/View
现在,我们已经知道了Model/View
大致的思路就是:我们自己有一个数据结构Data
(甚至没有结构,只有一堆散装变量也无伤大雅),然后搞一个Model
来解析它们,最后通过View
把Data
显示出来。
那本着批判性思维,可以毫不客气地说:就这?我不搞那么麻烦又Model
又View
的,直接拖一堆控件一个个对应上就好了,友谊的小船我一个人也能划!
那什么情况下我们使用Model/View
会更好呢?以下是笔者能想到的场景,仅供参考~
3.1 数据有规律/规模/维度变化
- 规律:典型地,如果底层是一个二维数组,采用
QTableView
就几乎完美; - 规模:20个的数据拖控件还是可以接受的,如果200个要拖控件那就可以裂开了;但是如果数据是有规律的,只需要定义
Model
的解析模型即可,剩下的交给View
; - 维度变化:如果一开始不知道有多少数据,这个要想拖控件就不太灵了;当然也可以采用
new
在运行时创建控件,再用合适的QLayout
进行布局,但是如果创建/删除比较频繁(比如10Hz)很容易导致界面卡死;当然,也可以先创建好预留对象,等使用的时候再显示出来,形成一套缓存机制……emmm,开心就好 😃……反观Model/View
底层的效率一般比自己实现的效率要更高(大佬请别喷),该用就用吧~
3.2 视图与数据不是对象关联
听起来比较晦涩,举个例子:
界面要显示学生信息,但是有很多个学生,界面上的数据就不是与某个对象关联了。更直观地说:没法拖控件然后connect
了;当然,也可以采用一个指针指向当前学生的对象地址,然后使用lambda
表达式连接相关信号,当更换显示的学生时emit
一个刷新界面的信号 😃……
似乎总能想到办法来用connect
和创建控件结合,以绕过Model/View
的使用……但是,接下来的内容,可能就不会那么容易了。
3.3 数据需要在视图中大面积修改
比如一个要直接显示5个学生的信息,每个学生的信息还需要在界面直接能修改,再采用connect
来做就直接裂开吧。
这边涉及到了在视图上更改数据,采用connect
方式的话,比起只读取显示,代码量直接翻倍了。
3.4 时间紧任务重
为什么现在岗位分成了前端后端,浅显地理解就是一个人在规定时间无法完成前后端的工作。
到此可能都有点忘了,Model/View
的初衷就是视图显示与底层数据分开,降低工作耦合。
所以,在软件开发中使用Model/View
思想无疑是正确的,即使时间足够充裕,没有那么多苛刻条件和奇怪需求,也建议使用Model/View
。
4. 小结
- Qt中的
Model/View
框架起源于MVC
框架,核心思想是降低工作耦合(前后端分开); - 思路是先有底层数据
Data
,然后采用一个Model
定义数据映射解析规则,最后View
通过与Model
交互实现数据的显示和修改; Delegate
这个👻先不用去理会它(以免被劝退);- 无论什么情况,都建议遵循降低耦合的思想去编码,建议使用
Model/View
框架。
如有错误欢迎指正,共同进步~
今天你学废了吗?