1. 两者都是MVC的模式,但是Shutter的model是二维数组,Blind的model是树型的,它和JFace的TreeViewer是类似的
2. 两者都是一些常见组件和自定义组件的合成。Shutter用了CoolButton和ScrollList。Blind用了Slat和QTree。实际上,Slat是CoolButton的精简版本(删了一些不常用的功能和少量的修改),只是名字不同。并且Blind在这方面比Shutter灵活,因为Shutter的内容区域只能是ScrollList,Blind的内容区可以是Composite。
3. Shutter没有Item的概念,Blind参照了TreeViewer的实现,使用了Item来对应model,也就是在QTree中使用了自定义的Item对象QItem。
4. Shutter把model直接映射为一个CoolButton,所以好友一多,效率就低。QTree则是纯绘制的。所以当时看了SWT的一些代码,设计了QTree的重绘算法。在绘画事件的时候,QTree会检查哪些Item需要重画(当然不是最优的,基本上凑合了一下),然后把绘画事件转发给QItem,由QItem自己来重绘自己。所以Blind的速度自然就快了。
5. 在布局上,Shutter使用的是自定义的SortLayout,Blind用的是SWT自带的GridLayout。从3.0的时候开始,GridData有了一个exclude属性,Blind就利用这个实现内容区的显示和隐藏
6. QQ里面,好友头像旁边可以显示摄像头图标,显示手机图标,等等。Shutter不支持这些小特性。所以QTree在设计的时候考虑了这些,主要反映在QItem的实现中。主要有这么几个概念需要说明一下:
a) 摄像头图标,手机图标,这些东西都是显示在头像旁边的,我把它叫做附件(Attachment)。附件有最大个数限制,目前代码里面是最多4个附件,你可以修改源代码调整最大个数。附件放在什么地方,是在重画算法里面计算的,保证了附件按一定规律摆放,不会重叠
b) 离开状态的图标,就是那个N/A字样的图标,它是显示在头像的右下角,和头像是重叠的,我把这种叫做装饰(Decoration)。装饰最多4个,可以分别装饰在头像的4个角
所以呢,QTree就可以支持这些小特性了,你看我自己添加了一个QQ没有的“好友置顶”的功能,置顶的好友会添加一个大头针的附件图标,就是这样的来由了。
7. Shutter和Blind都有标签编辑的功能,但是由于Shutter把model映射为CoolButton,所以编辑功能是在CoolButton里面提供的,实现起来容易一些。QTree是一个纯绘制的组件,为了实现Item的标签编辑,我实现了一个ControlEditor的子类。具体细节就不说了,反正也就是看看SWT的代码,琢磨了一下,如今细节也不太记得了。大致的原理很简单,你要编辑Item标签的时候,就新建一个Text控件,然后把Text定位到标签的位置,然后要监视Text的FocusEvent和KeyEvent,同时要注意在卷滚条滚动的时候调整Text的位置,编辑完了就释放这个Text。像这样的功能,可能不实践一下你觉得它很神奇,做过之后就发现原来就是这么简单。
8. 头像的跳动和闪烁这样的功能,CoolButton和QTree都有,但是QTree更灵活一些,QTree的动画实现很简单,用一个列表保存哪些Item正在显示动画,然后在重画的时候就画下一帧就可以了。不过下一帧到底画什么是可以自定义的,可以通过实现IEffect接口来自定义动画方式,所以说QTree比CoolButton灵活一些。
9. 由于Blind是树型的,所以还考虑了最大层数,每层的缩进量,每层的图标大小等功能。本来开始想能够设置每个Item的这些细节,但是太烦,后来想了想,觉得也没什么意义,还是针对每层设置算了。